840 Stimmen

Warum sind die "privaten" Methoden von Python nicht wirklich privat?

Python gibt uns die Möglichkeit, "private" Methoden und Variablen innerhalb einer Klasse zu erstellen, indem wir dem Namen einen doppelten Unterstrich voranstellen, wie hier: __myPrivateMethod() . Wie kann man dann dieses Phänomen erklären?

>>>> class MyClass:
...     def myPublicMethod(self):
...             print 'public method'
...     def __myPrivateMethod(self):
...             print 'this is private!!'
...
>>> obj = MyClass()

>>> obj.myPublicMethod()
public method

>>> obj.__myPrivateMethod()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: MyClass instance has no attribute '__myPrivateMethod'

>>> dir(obj)
['_MyClass__myPrivateMethod', '__doc__', '__module__', 'myPublicMethod']

>>> obj._MyClass__myPrivateMethod()
this is private!!

Was ist denn los?!

Für diejenigen, die das nicht ganz verstanden haben, werde ich das ein wenig erklären.

>>> class MyClass:
...     def myPublicMethod(self):
...             print 'public method'
...     def __myPrivateMethod(self):
...             print 'this is private!!'
...
>>> obj = MyClass()

Ich erstelle eine Klasse mit einer öffentlichen Methode und einer privaten Methode und instanziiere sie.

Als nächstes rufe ich die öffentliche Methode auf.

>>> obj.myPublicMethod()
public method

Als nächstes versuche ich, die private Methode aufzurufen.

>>> obj.__myPrivateMethod()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: MyClass instance has no attribute '__myPrivateMethod'

Hier sieht alles gut aus; wir sind nicht in der Lage, es zu nennen. Es ist in der Tat "privat". Nun, eigentlich ist es das nicht. Laufend dir() auf das Objekt zeigt eine neue magische Methode, die Python auf magische Weise für alle Ihre "privaten" Methoden erstellt.

>>> dir(obj)
['_MyClass__myPrivateMethod', '__doc__', '__module__', 'myPublicMethod']

Der Name dieser neuen Methode ist immer ein Unterstrich, gefolgt vom Klassennamen, gefolgt vom Methodennamen.

>>> obj._MyClass__myPrivateMethod()
this is private!!

So viel zur Verkapselung, was?

Auf jeden Fall hatte ich immer gehört, dass Python keine Kapselung unterstützt, also warum es überhaupt versuchen? Was ist der Grund?

42 Stimmen

Das Gleiche gilt für Java oder C#, wenn Sie Reflection verwenden (was Sie dort ja auch tun).

7 Stimmen

Sie wurde zum Zweck des Unit-Tests erstellt, so dass Sie diesen "Hack" verwenden können, um die privaten Methoden Ihrer Klasse von außen zu testen.

37 Stimmen

Ist das Testen privater Methoden nicht ein Anti-Muster? Private Methoden werden mit Sicherheit in einer öffentlichen Methode verwendet, sonst bleiben sie für immer ungenutzt. Und der richtige Weg, private Methoden zu testen (basierend auf dem, was ich bisher von ThoughtWorks gelernt habe), ist, dass man nur Tests für öffentliche Methoden schreibt, die alle Fälle abdecken. Wenn das gut funktioniert, braucht man private Methoden gar nicht von außen zu testen.

38voto

Maximilian Punkte 4540

Es ist ja nicht so, dass man die Privatheit von Mitgliedern in keiner Sprache umgehen kann (Zeigerarithmetik in C++ und Reflexionen in .NET/Java).

Der Punkt ist, dass Sie einen Fehler erhalten, wenn Sie versuchen, die private Methode versehentlich aufzurufen. Aber wenn Sie sich selbst in den Fuß schießen wollen, dann tun Sie es doch einfach.

Sie versuchen doch auch nicht, Ihr Material durch OO-Kapselung zu sichern, oder?

2 Stimmen

Ganz und gar nicht. Ich möchte lediglich darauf hinweisen, dass es seltsam ist, dem Entwickler eine einfache und meiner Meinung nach zu magische Möglichkeit zu geben, auf "private" Grundstücke zuzugreifen.

2 Stimmen

Ja, ich habe nur versucht, den Punkt zu illustrieren. Wenn man es privat macht, sagt man einfach, dass man nicht direkt darauf zugreifen sollte, indem man den Compiler dazu bringt, sich zu beschweren. Aber wenn man es wirklich will, kann man es tun. Aber ja, in Python ist es einfacher als in den meisten anderen Sprachen.

7 Stimmen

In Java kann man Dinge durch Kapselung sichern, aber dazu muss man schlau sein und den nicht vertrauenswürdigen Code in einem SecurityManager ausführen und sehr vorsichtig sein. Selbst Oracle macht das manchmal falsch.

21voto

Moradnejad Punkte 2977

Wichtiger Hinweis:

Jeder Bezeichner der Form __name (mindestens zwei führende Unterstriche, höchstens ein nachgestellter Unterstrich) wird öffentlich ersetzt durch _classname__name , donde classname ist der aktuelle Klassenname ohne führende(n) Unterstrich(e).

Deshalb, __name ist nicht direkt zugänglich, sondern kann als _classname__name .

Dies bedeutet jedoch nicht, dass Sie Ihre privaten Daten schützen können, da diese leicht zugänglich sind, indem Sie den Namen der Variablen ändern.

Quelle:

Abschnitt "Private Variablen" in der offiziellen Dokumentation: https://docs.python.org/3/tutorial/classes.html#tut-private

Beispiel

class Cat:
    def __init__(self, name='unnamed'):
        self.name = name
    def __print_my_name(self):
        print(self.name)

tom = Cat()
tom.__print_my_name() #Error
tom._Cat__print_my_name() #Prints name

3 Stimmen

Das ist keine wichtige Neuerung, das war schon immer so. Ersetzen Sie die 3 durch eine 2 in Ihrem Link, docs.python.org/2/tutorial/classes.html#tut-private fast genau denselben Text, den Sie in Ihrer Antwort angegeben haben. NICHT ein Update.

1 Stimmen

Auch das ist nicht wahr: __name ist nicht "privat", da sie über _classname__name . Etwas Zugängliches ist NICHT "privat". So etwas wie ein "privates" Attribut gibt es in keiner der großen Computersprachen (AFAIK), so einfach ist das. Man kann sagen, dass lokale Variablen in einer Methode "privat" sind, aber nur, wenn sie von außerhalb der Methode in keiner Weise zugänglich sind.

0 Stimmen

Das wird bereits in der Antwort erklärt. Mit dieser Definition und der Aussage, dass "es so etwas wie ein privates Attribut in keiner wichtigen Computersprache gibt", müssen wir "privat" in Programmiersprachen neu definieren. Aber bis dahin können wir das verwenden, was wir haben, und es als privat bezeichnen, da es in den offiziellen Dokumenten als "privat" bezeichnet wird.

13voto

Ross Punkte 1395

Ähnlich verhält es sich, wenn Modulattributnamen mit einem einzelnen Unterstrich beginnen (z. B. _foo).

So benannte Modulattribute werden nicht in ein importierendes Modul kopiert, wenn die Funktion from* Methode, z.B.:

from bar import *

Dabei handelt es sich jedoch um eine Konvention und nicht um eine sprachliche Einschränkung. Dies sind keine privaten Attribute; sie können von jedem Importeur referenziert und manipuliert werden. Einige argumentieren, dass Python aus diesem Grund keine echte Kapselung implementieren kann.

12voto

ctcherry Punkte 27220

Das ist nur eine der Entscheidungen, die das Sprachdesign trifft. In gewisser Hinsicht sind sie gerechtfertigt. Sie sorgen dafür, dass man sich ziemlich weit aus dem Fenster lehnen muss, um die Methode aufzurufen, und wenn man sie wirklich so dringend braucht, muss man einen ziemlich guten Grund haben!

Als mögliche Anwendungen kommen Debugging-Hooks und Tests in Frage, die natürlich verantwortungsvoll eingesetzt werden.

5voto

Afshin Amiri Punkte 3118

Das wichtigste Anliegen bei privaten Methoden und Attributen ist es, den Entwicklern mitzuteilen, dass sie diese nicht außerhalb der Klasse aufrufen sollen, und das ist die Kapselung. Man kann die Sicherheit von Kapselung missverstehen. Wenn man absichtlich eine Syntax wie die von Ihnen erwähnte (unten) verwendet, will man keine Verkapselung.

obj._MyClass__myPrivateMethod()

Ich habe von C# migriert und zunächst war es auch für mich seltsam, aber nach einer Weile kam ich auf die Idee, dass nur die Art und Weise, dass Python-Code-Designer denken über OOP ist anders.

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