734 Stimmen

Gibt es in Python "private" Variablen in Klassen?

Ich komme aus der Java-Welt und lese Bruce Eckels' Python 3 Muster, Rezepte und Redewendungen .

Bei der Lektüre über Klassen wird darauf hingewiesen, dass in Python keine Instanzvariablen deklariert werden müssen. Man verwendet sie einfach im Konstruktor, und schon sind sie da.

So zum Beispiel:

class Simple:
    def __init__(self, s):
        print("inside the simple constructor")
        self.s = s

    def show(self):
        print(self.s)

    def showMsg(self, msg):
        print(msg + ':', self.show())

Wenn das wahr ist, dann kann jedes Objekt der Klasse Simple kann einfach den Wert der Variablen s außerhalb des Unterrichts.

Zum Beispiel:

if __name__ == "__main__":
    x = Simple("constructor argument")
    x.s = "test15" # this changes the value
    x.show()
    x.showMsg("A message")

In Java wurde uns beigebracht, dass es öffentliche/private/geschützte Variablen gibt. Diese Schlüsselwörter sind sinnvoll, weil man manchmal Variablen in einer Klasse haben möchte, auf die niemand außerhalb der Klasse Zugriff hat.

Warum ist das in Python nicht erforderlich?

1135voto

Kirk Strauser Punkte 29205

Das ist kulturell bedingt. In Python schreibt man nicht in die Instanz- oder Klassenvariablen anderer Klassen. In Java hindert Sie nichts daran, das Gleiche zu tun, wenn Sie wirklich wollen - schließlich können Sie jederzeit den Quelltext der Klasse selbst bearbeiten, um denselben Effekt zu erzielen. Python lässt den Anschein von Sicherheit fallen und ermutigt die Programmierer, verantwortlich zu handeln. In der Praxis funktioniert das sehr gut.

Wenn Sie aus irgendeinem Grund private Variablen emulieren wollen, können Sie jederzeit die __ Präfix von PEP 8 . Python verstümmelt die Namen von Variablen wie __foo so dass sie für Code außerhalb der Klasse, die sie enthält, nicht leicht sichtbar sind (obwohl Sie wenn man entschlossen genug ist, sie zu umgehen, genau wie Sie die Schutzmaßnahmen von Java zu umgehen, wenn Sie daran arbeiten).

Nach der gleichen Konvention ist die _ Präfix bedeutet bleiben Sie weg, auch wenn Sie technisch nicht daran gehindert werden . Man spielt nicht mit den Variablen einer anderen Klasse herum, die aussehen wie __foo o _bar .

236voto

watashiSHUN Punkte 8606

Private Variablen in Python sind mehr oder weniger ein Hack: der Interpreter benennt die Variable absichtlich um.

class A:
    def __init__(self):
        self.__var = 123
    def printVar(self):
        print self.__var

Wenn Sie nun versuchen, auf __var außerhalb der Klassendefinition, schlägt es fehl:

>>> x = A()
>>> x.__var # this will return error: "A has no attribute __var"

>>> x.printVar() # this gives back 123

Aber damit kann man sich leicht abfinden:

>>> x.__dict__ # this will show everything that is contained in object x
               # which in this case is something like {'_A__var' : 123}

>>> x._A__var = 456 # you now know the masked name of private variables
>>> x.printVar() # this gives back 456

Sie wissen wahrscheinlich, dass Methoden in OOP so aufgerufen werden: x.printVar() => A.printVar(x) wenn A.printVar() kann auf ein Feld in x kann auf dieses Feld auch zugegriffen werden außerhalb A.printVar() ...schließlich werden Funktionen für die Wiederverwendbarkeit erstellt, den darin enthaltenen Anweisungen wird keine besondere Macht verliehen.

Das Spiel ist anders, wenn ein Compiler beteiligt ist ( Datenschutz ist ein Konzept auf Compiler-Ebene ). Es kennt die Klassendefinition mit Zugriffskontrollmodifikatoren, so dass es einen Fehler melden kann, wenn die Regeln zur Kompilierungszeit nicht eingehalten werden

37voto

Ardavan Punkte 1866

Wie in vielen der obigen Kommentare richtig erwähnt, sollten wir das Hauptziel der Zugangsmodifikatoren nicht vergessen: Den Benutzern des Codes zu helfen, zu verstehen, was geändert werden soll und was nicht. Wenn Sie ein privates Feld sehen, dann machen Sie nicht damit rum. Es handelt sich also hauptsächlich um syntaktischen Zucker, der in Python leicht durch _ und __ erreicht werden kann.

28voto

Hatatister Punkte 738

In Python gibt es keine privaten Variablen wie in C++ oder Java. Sie könnten auch jederzeit auf jede Mitgliedsvariable zugreifen, wenn Sie das wollten. Allerdings braucht man in Python keine privaten Variablen, denn in Python ist es nicht schlimm, die Mitgliedsvariablen der Klasse offenzulegen. Wenn Sie eine Mitgliedsvariable kapseln müssen, können Sie dies später mit "@property" tun, ohne den bestehenden Client-Code zu verändern.

In Python wird der einzelne Unterstrich "_" verwendet, um anzuzeigen, dass eine Methode oder Variable nicht als Teil der öffentlichen API einer Klasse angesehen wird und dass sich dieser Teil der API zwischen verschiedenen Versionen ändern kann. Sie können diese Methoden/Variablen verwenden, aber Ihr Code könnte kaputt gehen, wenn Sie eine neuere Version dieser Klasse verwenden.

Der doppelte Unterstrich "__" steht nicht für eine "private Variable". Sie verwenden ihn, um Variablen zu definieren, die "klassenlokal" sind und die nicht einfach von Unterklassen überschrieben werden können. Der Name der Variablen wird dadurch verfälscht.

Zum Beispiel:

class A(object):
    def __init__(self):
        self.__foobar = None # will be automatically mangled to self._A__foobar

class B(A):
    def __init__(self):
        self.__foobar = 1 # will be automatically mangled to self._B__foobar

Der Name von self.__foobar wird in Klasse A automatisch in self._A__foobar umgewandelt. In Klasse B wird er in self._B__foobar umgewandelt. Jede Unterklasse kann also ihre eigene Variable __foobar definieren, ohne ihre Elternvariable(n) zu überschreiben. Aber nichts hindert Sie daran, auf Variablen zuzugreifen, die mit doppelten Unterstrichen beginnen. Allerdings verhindert die Namensvermischung, dass Sie diese Variablen/Methoden zufällig aufrufen.

Ich empfehle Ihnen dringend, sich Raymond Hettingers Pythons Werkzeugkasten für die Klassenentwicklung von Pycon 2013, das ein gutes Beispiel dafür liefert, warum und wie Sie @property und "__"-Instanzvariablen verwenden sollten.

Wenn Sie öffentliche Variablen ausgesetzt haben und diese kapseln müssen, können Sie @property verwenden. Sie können also mit der einfachsten Lösung beginnen. Sie können Mitgliedsvariablen öffentlich lassen, es sei denn, Sie haben einen konkreten Grund, dies nicht zu tun. Hier ist ein Beispiel:

class Distance:
    def __init__(self, meter):
        self.meter = meter

d = Distance(1.0)
print(d.meter)
# prints 1.0

class Distance:
    def __init__(self, meter):
        # Customer request: Distances must be stored in millimeters.
        # Public available internals must be changed.
        # This would break client code in C++.
        # This is why you never expose public variables in C++ or Java.
        # However, this is python.
        self.millimeter = meter * 1000

    # In python we have @property to the rescue.
    @property
    def meter(self):
        return self.millimeter *0.001

    @meter.setter
    def meter(self, value):
        self.millimeter = meter * 1000

d = Distance(1.0)
print(d.meter)
# prints 1.0

18voto

Shayne Punkte 1586

Es gibt eine Variante der privaten Variablen in der Unterstrichkonvention.

In [5]: class Test(object):
   ...:     def __private_method(self):
   ...:         return "Boo"
   ...:     def public_method(self):
   ...:         return self.__private_method()
   ...:     

In [6]: x = Test()

In [7]: x.public_method()
Out[7]: 'Boo'

In [8]: x.__private_method()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-8-fa17ce05d8bc> in <module>()
----> 1 x.__private_method()

AttributeError: 'Test' object has no attribute '__private_method'

Es gibt einige feine Unterschiede, aber für die ideologische Reinheit des Programmiermusters ist das gut genug.

Es gibt Beispiele für @private Dekoratoren, die das Konzept besser umsetzen, aber YMMV. Man könnte auch eine Klassendefinition schreiben die meta verwendet

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X