Definieren von Funktionen für private Module in Python

238

Laut http://www.faqs.org/docs/diveintopython/fileinfo_private.html :

Wie die meisten Sprachen hat Python das Konzept privater Elemente:

  • Private Funktionen, die nicht von außerhalb ihres Moduls aufgerufen werden können

Wenn ich jedoch zwei Dateien definiere:

#a.py
__num=1

und:

#b.py
import a
print a.__num

Wenn ich b.pyes starte, wird es 1ohne Ausnahme ausgedruckt. Ist Diveintopython falsch oder habe ich etwas falsch verstanden? Und ist es eine Möglichkeit , tun ein Moduls Funktion als privat definieren?

Olamundo
quelle
Es ist nicht so, dass Diveintopython falsch ist, aber in ihrem Beispiel: >>> import fileinfo >>> m = fileinfo.MP3FileInfo() >>> m.__parse("/music/_singles/kairo.mp3") 1 Traceback (innermost last): File "<interactive input>", line 1, in ? AttributeError: 'MP3FileInfo' instance has no attribute '__parse' fileinfo.MP3FileInfo () ist eine Instanz der Klasse. Dies gibt diese Ausnahme, wenn Sie einen doppelten Unterstrich verwenden. Während Sie in Ihrem Fall keine Klasse erstellt haben, haben Sie nur ein Modul erstellt. Siehe auch: stackoverflow.com/questions/70528/…
Homero Esmeraldo

Antworten:

323

In Python hängt "Datenschutz" von der Zustimmung der Erwachsenen ab - Sie können dies nicht erzwingen (genauso wenig wie im wirklichen Leben ;-). Ein einziger führender Unterstrich bedeutet , dass Sie nicht sollte den Zugriff auf mich „von außen“ - zwei führenden Unterstrichen (w / o Nachlauf Unterstreicht) trägt die Botschaft noch mehr Nachdruck ... aber am Ende, es hängt immer noch von sozialem Konvention und Konsens: Pythons Selbstbeobachtung ist so stark, dass Sie nicht jedem anderen Programmierer auf der Welt Handschellen anlegen können , um Ihre Wünsche zu respektieren.

((Übrigens, obwohl es ein streng gehütetes Geheimnis ist, gilt dies auch für C ++: Bei den meisten Compilern ist eine einfache #define private publicZeile vor dem #includeErstellen Ihrer .hDatei alles, was geschickte Codierer benötigen, um Ihre "Privatsphäre" zu verfälschen ...! -) )

Alex Martelli
quelle
82
Ihr Hinweis zu C ++ ist falsch. Mit #define private public ändern Sie den Code, der an den Compiler gesendet wird. Dort findet die Namensverknüpfung statt.
Rhinoinrepose
14
Auch das C ++ Mangeln ist dunkel, aber kaum geheim. Sie können auch eine von C ++ erzeugte Binärdatei "introspektieren". OT, sorry.
Prof. Falken Vertrag verletzt
47
Als Update für @rhinoinrepose ist es nicht nur falsch, es ist ein undefiniertes Verhalten gemäß dem Standard , ein Schlüsselwort mit einem Präprozessor-Makro neu zu definieren.
Cory Kramer
3
@AlexMartelli Ist nicht static void foo()so privat wie es nur geht. Es ist zumindest für den Linker verborgen, und die Funktion kann durch Inlining vollständig entfernt werden.
user877329
3
Im wirklichen Leben werden Menschen strafrechtlich verfolgt, wenn sie gegen die Gesetze verstoßen
Lay González
288

Es kann zu Verwechslungen zwischen Klassenprivaten und Modulprivaten kommen .

Ein privates Modul beginnt mit einem Unterstrich.
Ein solches Element wird bei Verwendung der from <module_name> import *Form des Importbefehls nicht mitkopiert . Es wird jedoch importiert, wenn die import <moudule_name>Syntax verwendet wird ( siehe Antwort von Ben Wilhelm ).
Entfernen Sie einfach einen Unterstrich aus der a .__ Nummer des Beispiels der Frage, und es wird nicht in Modulen angezeigt, die a.py mithilfe der from a import *Syntax importieren .

Eine private Klasse beginnt mit zwei Unterstrichen (auch bekannt als dunder ie d-ouble underscore). Bei einer
solchen Variablen wird der Name "entstellt", um den Klassennamen usw. einzuschließen. Auf
sie kann auch außerhalb der Klassenlogik über den verstümmelten Namen zugegriffen werden.
Obwohl die Namensverknüpfung als milde Verhinderungsmaßnahme gegen unbefugten Zugriff dienen kann, besteht ihr Hauptzweck darin, mögliche Namenskollisionen mit Klassenmitgliedern der Ahnenklassen zu verhindern. Siehe Alex Martellis lustigen, aber genauen Hinweis auf einwilligende Erwachsene, während er die Konvention beschreibt, die in Bezug auf diese Variablen verwendet wird.

>>> class Foo(object):
...    __bar = 99
...    def PrintBar(self):
...        print(self.__bar)
...
>>> myFoo = Foo()
>>> myFoo.__bar  #direct attempt no go
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute '__bar'
>>> myFoo.PrintBar()  # the class itself of course can access it
99
>>> dir(Foo)    # yet can see it
['PrintBar', '_Foo__bar', '__class__', '__delattr__', '__dict__', '__doc__', '__
format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__
', '__subclasshook__', '__weakref__']
>>> myFoo._Foo__bar  #and get to it by its mangled name !  (but I shouldn't!!!)
99
>>>
mjv
quelle
Nun, bis. Gibt es einen Grund, warum sie die Modulebene nicht erzwingen __private_function? Ich bin darauf gestoßen und habe dadurch Fehler gemacht.
Santa
Vielen Dank für die freundlichen Worte @Terrabits, aber ich stehe gerne hinter Alex (weit dahinter!) In allen Dingen 'Python' an zweiter Stelle. Darüber hinaus sind seine Antworten in der Regel prägnanter und humorvoller, während Alex aufgrund seiner umfangreichen Beiträge zur Sprache und zur Gemeinschaft ein hohes Maß an Autorität bewahrt.
mjv
1
@mjv Das war so eine hilfreiche Erklärung! Danke dir! Ich war eine Weile ziemlich verwirrt über dieses Verhalten. Ich wünschte, die Wahl wäre gewesen, einen anderen Fehler als einen AttributeError auszulösen, wenn Sie versucht hätten, direkt auf die private Klasse zuzugreifen. Vielleicht wäre ein "PrivateAccessError" oder etwas expliziter / hilfreicher gewesen. (Da der Fehler, dass es kein Attribut hat, nicht wirklich wahr ist).
HFBrowning
82

Diese Frage wurde nicht vollständig beantwortet, da der Datenschutz von Modulen nicht rein konventionell ist und die Verwendung des Imports den Datenschutz von Modulen je nach Verwendungszweck möglicherweise erkennt oder nicht.

Wenn Sie eine private Namen in einem Modul definieren, diese Namen werden werden in jedes Skript importiert, die die Syntax verwendet, ‚Import module_name‘. Angenommen, Sie haben in Ihrem Beispiel das Modul private, _num, in a.py wie folgt korrekt definiert.

#a.py
_num=1

..Sie können in b.py mit dem Symbol für den Modulnamen darauf zugreifen:

#b.py
import a
...
foo = a._num # 1

Um nur Nicht-Privates aus a.py zu importieren, müssen Sie die from- Syntax verwenden:

#b.py
from a import *
...
foo = _num # throws NameError: name '_num' is not defined

Aus Gründen der Übersichtlichkeit ist es jedoch besser, beim Importieren von Namen aus Modulen explizit anzugeben, als sie alle mit einem '*' zu importieren:

#b.py
from a import name1 
from a import name2
...
Ben Wilhelm
quelle
1
Wo geben Sie an, welche Funktionen / Bibliotheken importiert werden? in der init .py?
FistOfFury
Es besteht keine Gefahr von Namenskollisionen , wenn _namesaufgerufen werden mit import a- sie sind Zugriffe als a._nameswenn mit diesem Stil.
Josiah Yoder
@FistOfFury Ja, Sie geben die in die __init__.pyDatei importierten Funktionen an . Sehen Sie hier für einige Hilfe , dass auf.
Mike Williamson
29

Python erlaubt private Klassenmitglieder mit dem doppelten Unterstrichpräfix. Diese Technik funktioniert nicht auf Modulebene, daher denke ich, dass dies ein Fehler in Dive Into Python ist.

Hier ist ein Beispiel für private Klassenfunktionen:

class foo():
    def bar(self): pass
    def __bar(self): pass

f = foo()
f.bar()   # this call succeeds
f.__bar() # this call fails
Andrew Hare
quelle
2
Ich denke, die Absicht des OP ist es, Funktionen zu schreiben, auf die beispielsweise außerhalb eines kommerziellen Pakets nicht zugegriffen werden kann. In dieser Hinsicht ist diese Antwort nicht vollständig. Auf die Funktion __bar () kann weiterhin von außen über f._foo__bar () zugegriffen werden. Daher machen die doppelt führenden Unterstriche es nicht privat.
SevakPrime
24

Sie können eine innere Funktion hinzufügen:

def public(self, args):
   def private(self.root, data):
       if (self.root != None):
          pass #do something with data

So etwas, wenn Sie wirklich dieses Maß an Privatsphäre benötigen.

Ilian Zapryanov
quelle
9
Warum ist das nicht die beste Antwort?
Safay
2

Dies ist eine alte Frage, aber sowohl modulierte private (ein Unterstrich) als auch klassenprivate (zwei Unterstriche) verstümmelte Variablen werden jetzt in der Standarddokumentation behandelt:

Das Python-Tutorial » Klassen » Private Variablen

user1338062
quelle
1

eingebettet in Verschlüsse oder Funktionen ist eine Möglichkeit. Dies ist in JS üblich, wird jedoch nicht für Nicht-Browser-Plattformen oder Browser-Mitarbeiter benötigt.

In Python scheint es ein bisschen seltsam, aber wenn etwas wirklich versteckt werden muss, könnte das der Weg sein. Mehr auf den Punkt zu bringen, die Python-API zu verwenden und Dinge zu behalten, die im C (oder einer anderen Sprache) versteckt werden müssen, ist wahrscheinlich der beste Weg. Andernfalls würde ich den Code in eine Funktion einfügen, diesen aufrufen und die zu exportierenden Elemente zurückgeben lassen.

Mars Ruhm
quelle
-11

Python verfügt über drei Modi über., Privat, öffentlich und geschützt. Beim Importieren eines Moduls kann nur auf den öffentlichen Modus zugegriffen werden. Daher können private und geschützte Module nicht von außerhalb des Moduls aufgerufen werden, dh wenn es importiert wird.

sravan
quelle