it-swarm-eu.dev

Warum sind Pythons "private" Methoden nicht wirklich privat?

Python gibt uns die Möglichkeit, "private" Methoden und Variablen innerhalb einer Klasse zu erstellen, indem dem Namen doppelte Unterstriche vorangestellt werden: __myPrivateMethod(). Wie kann man das 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 "", line 1, in 
AttributeError: MyClass instance has no attribute '__myPrivateMethod'
>>> dir(obj)
['_MyClass__myPrivateMethod', '__doc__', '__module__', 'myPublicMethod']
>>> obj._MyClass__myPrivateMethod()
this is private!!

Was ist das Problem?!

Ich erkläre das ein wenig für diejenigen, die das nicht ganz verstanden haben.

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

Was ich dort gemacht habe, ist eine Klasse mit einer öffentlichen Methode und einer privaten Methode zu erstellen und zu instanziieren.

Als nächstes nenne ich seine öffentliche Methode.

>>> obj.myPublicMethod()
public method

Als Nächstes versuche ich, seine private Methode aufzurufen.

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

Hier sieht alles gut aus; Wir können es nicht nennen. Es ist tatsächlich "privat". Nun, eigentlich ist es nicht so. Das Ausführen von dir () am Objekt enthüllt eine neue magische Methode, die Python magisch 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 Einkapselung, was?

Auf jeden Fall hatte ich immer gehört, dass Python die Kapselung nicht unterstützt, warum also überhaupt versuchen? Was gibt?

557
willurd

Der Name Scrambling wird verwendet, um sicherzustellen, dass Unterklassen die privaten Methoden und Attribute ihrer Superklassen nicht versehentlich überschreiben. Es ist nicht dazu gedacht, vorsätzlichen Zugriff von außen zu verhindern.

Zum Beispiel:

>>> class Foo(object):
...     def __init__(self):
...         self.__baz = 42
...     def foo(self):
...         print self.__baz
...     
>>> class Bar(Foo):
...     def __init__(self):
...         super(Bar, self).__init__()
...         self.__baz = 21
...     def bar(self):
...         print self.__baz
...
>>> x = Bar()
>>> x.foo()
42
>>> x.bar()
21
>>> print x.__dict__
{'_Bar__baz': 21, '_Foo__baz': 42}

Natürlich bricht es zusammen, wenn zwei verschiedene Klassen denselben Namen haben.

524
Alya

Beispiel für eine private Funktion

import re
import inspect

class MyClass :

    def __init__(self) :
        pass

    def private_function ( self ) :
        try :
            function_call = inspect.stack()[1][4][0].strip()

            # See if the function_call has "self." in the begining
            matched = re.match( '^self\.', function_call )
            if not matched :
                print 'This is Private Function, Go Away'
                return
        except :
            print 'This is Private Function, Go Away'
            return

        # This is the real Function, only accessible inside class #
        print 'Hey, Welcome in to function'

    def public_function ( self ) :
        # i can call private function from inside the class
        self.private_function()

### End ###
206
arun

Als ich zum ersten Mal vonJavanachPythonkam, war ich gehasst. Es hat mich zu Tode erschreckt.

Heute könnte es nur das eine sein das mag ich am meisten an Python.

Ich liebe es, auf einer Plattform zu sein, auf der sich die Leute gegenseitig vertrauen und nicht das Gefühl haben, undurchdringliche Mauern um ihren Code herum zu bauen. Wenn eine API in stark gekapselten Sprachen einen Fehler aufweist und Sie herausgefunden haben, was schief geht, können Sie ihn möglicherweise immer noch nicht umgehen, da die erforderliche Methode privat ist. In Python lautet die Einstellung: "sicher". Wenn Sie denken, Sie verstehen die Situation, vielleicht haben Sie sie sogar gelesen, dann können wir nur "viel Glück!" Sagen.

Denken Sie daran, dass die Einkapselung nicht einmal in geringem Maße mit "Sicherheit" zusammenhängt oder die Kinder vom Rasen fernhält. Es ist nur ein weiteres Muster, das zum besseren Verständnis einer Codebasis verwendet werden sollte.

156
Thomas Ahle

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

Streng genommen sind private Methoden zugänglich außerhalb ihrer Klasse, nur nicht leicht zugänglich. Nichts in Python ist wirklich privat; im Inneren, die Namen privater Methoden und Attribute sind entstellt und entmustert on the fly, um sie scheinen zu lassen unzugänglich durch ihre Vornamen. Sie kann auf die __parse-Methode von .__ zugreifen. MP3FileInfo-Klasse mit dem Namen _MP3FileInfo__parse. Bestätigen Sie, dass dies interessant ist, und versprechen Sie dann mache es niemals in echtem Code . Private Methoden sind privat für eine Grund, aber wie viele andere Dinge in Python, ihre Privatheit ist letztlich eine Frage der Konvention, nicht Macht.

134
xsl

Der allgemein verwendete Ausdruck lautet "Wir sind alle Erwachsenen hier einverstanden". Indem Sie einen einzelnen Unterstrich (nicht bloßstellen) oder einen doppelten Unterstrich (ausblenden) voranstellen, teilen Sie dem Benutzer Ihrer Klasse mit, dass das Mitglied auf irgendeine Weise "privat" sein soll. Sie vertrauen jedoch darauf, dass sich alle anderen verantwortungsvoll verhalten und das respektieren, es sei denn, sie haben einen zwingenden Grund (z. B. Debugger, Code-Vervollständigung).

Wenn Sie wirklich etwas privates benötigen, können Sie es in einer Erweiterung implementieren (z. B. in C für CPython). In den meisten Fällen lernen Sie jedoch einfach die Pythonic-Vorgehensweise.

86
Tony Meyer

Es ist nicht so, dass Sie absolut nicht in der Lage sind, Mitglieder in einer beliebigen Sprache zu behandeln (Zeigerarithmetik in C++, Reflections in .NET/Java).

Der Punkt ist, dass Sie eine Fehlermeldung erhalten, wenn Sie versuchen, die private Methode versehentlich aufzurufen. Aber wenn Sie sich in den Fuß schießen wollen, machen Sie es einfach.

Edit: Sie versuchen nicht, Ihre Sachen durch OO-Encapsulation zu sichern, oder?

32
Maximilian

Ein ähnliches Verhalten liegt vor, wenn die Modulattributnamen mit einem einzelnen Unterstrich beginnen (z. B. _foo).

Als solche benannte Modulattribute werden bei Verwendung der from*-Methode nicht in ein importierendes Modul kopiert, z.

from bar import *

Dies ist jedoch eine Konvention und keine Sprachbedingung. 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.

12
Ross

Es ist nur eine dieser Sprachenentscheidungen. In gewisser Hinsicht sind sie berechtigt. Sie machen es so, dass Sie ziemlich weit aus dem Weg gehen müssen, um die Methode aufzurufen, und wenn Sie sie wirklich so dringend brauchen, müssen Sie einen recht guten Grund haben!

Debugging-Hooks und Tests kommen mir als mögliche Anwendungen in den Sinn, die natürlich verantwortungsvoll eingesetzt werden.

12
ctcherry

Die Namenskonvention class.__stuff teilt dem Programmierer mit, dass er nicht von außen auf __stuff zugreifen soll. Die Namensmangel macht es unwahrscheinlich, dass jemand es aus Versehen tut.

Sie können dies zwar immer noch umgehen, es ist sogar noch einfacher als in anderen Sprachen (BTW lässt Sie dies auch), aber kein Python-Programmierer würde dies tun, wenn ihm die Kapselung wichtig ist.

11
Nickolay

Bei Python 3.4 ist dies das Verhalten:

>>> class Foo:
        def __init__(self):
                pass
        def __privateMethod(self):
                return 3
        def invoke(self):
                return self.__privateMethod()


>>> help(Foo)
Help on class Foo in module __main__:

class Foo(builtins.object)
 |  Methods defined here:
 |
 |  __init__(self)
 |
 |  invoke(self)
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)

 >>> f = Foo()
 >>> f.invoke()
 3
 >>> f.__privateMethod()
 Traceback (most recent call last):
   File "<pyshell#47>", line 1, in <module>
     f.__privateMethod()
 AttributeError: 'Foo' object has no attribute '__privateMethod'

https://docs.python.org/3/tutorial/classes.html#tut-private

Bitte beachten Sie, dass die Mangling-Regeln hauptsächlich dazu dienen, Unfälle zu vermeiden. es ist immer noch möglich, auf eine Variable zuzugreifen oder diese zu ändern, die als privat gilt. Dies kann sogar in besonderen Situationen hilfreich sein, beispielsweise im Debugger.

Selbst wenn die Frage alt ist, hoffe ich, dass mein Snippet hilfreich sein kann.

3
Alberto

Die wichtigste Sorge bei privaten Methoden und Attributen besteht darin, den Entwicklern mitzuteilen, sie nicht außerhalb der Klasse aufzurufen. Dies ist die Kapselung. Man kann die Sicherheit durch die Kapselung missverstehen. Wenn Sie die Syntax absichtlich so verwenden, möchten Sie keine Kapselung.

obj._MyClass__myPrivateMethod()

Ich bin von C # gewandert und anfangs war es auch für mich seltsam, aber nach einer Weile kam ich zu dem Gedanken, dass nur die Art und Weise, in der Python-Code-Designer über OOP denken, anders ist. 

2
Afshin Amiri

Warum sind Pythons 'private' Methoden eigentlich nicht privat?

Wie ich es verstehe, kann nicht privat sein. Wie könnte die Privatsphäre durchgesetzt werden?

Die offensichtliche Antwort lautet "Auf private Mitglieder kann nur über self zugegriffen werden", aber das würde nicht funktionieren - self ist in Python nichts Besonderes, es ist nichts anderes als ein häufig verwendeter Name für der erste Parameter einer Funktion.

1
user200783