Pourquoi les méthodes "privées" de Python ne sont-elles pas réellement privées?

Python nous donne la possibilité de créer des méthodes et des variables "privées" dans une classe en ajoutant deux underscores au nom, comme ceci: __myPrivateMethod() . Comment, alors, peut-on expliquer ce

>>> 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!!

c'est quoi le problème?!

je vais expliquer ceci un peu pour ceux qui n'ont pas tout à fait compris cela.

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

ce que j'ai fait là, c'est créer une classe avec une méthode publique et une méthode privée et l'instancier.

ensuite, j'appelle sa méthode publique.

>>> obj.myPublicMethod()
public method

ensuite, j'essaie d'appeler sa méthode privée.

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

tout a l'air bien ici; nous ne pouvons pas l'appeler. Il est, en fait, le "privé". En fait, non. Exécuter dir () sur l'objet révèle une nouvelle méthode magique que python crée magiquement pour toutes vos méthodes "privées".

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

cette nouvelle méthode nom est toujours un underscore, suivi du nom de la classe, suivi du nom de la méthode.

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

autant pour l'encapsulation, hein?

dans tous les cas, J'ai toujours entendu que Python ne supporte pas l'encapsulation, alors pourquoi essayer? Ce qui donne?

518
demandé sur Stefan van den Akker 2008-09-16 12:59:32

11 réponses

le brouillage du nom est utilisé pour s'assurer que les sous-classes ne supplantent pas accidentellement les méthodes privées et les attributs de leurs superclasses. Il n'est pas conçu pour empêcher l'accès délibéré de l'extérieur.

par exemple:

>>> 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}

bien sûr, il se décompose si deux classes différentes ont le même nom.

490
répondu Alya 2008-09-16 10:06:07

exemple de fonction privée

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 ###
201
répondu arun 2010-11-29 12:52:47

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

à proprement parler, les méthodes privées sont accessible à l'extérieur de leur classe, tout pas facilement accessible. Rien dans Python est vraiment privé; en interne, les noms de méthodes privées et les attributs sont altérés et non altérés à la volée pour les faire paraître inaccessibles par leurs prénoms. Vous peuvent accéder à l' __méthode d'analyse de la Classe MP3FileInfo par le nom _MP3FileInfo_ _ parse. Reconnaissez que c'est intéressant, alors promettez de jamais, jamais en vrai code. Les méthodes privées sont privées pour un raison, mais comme beaucoup d'autres choses dans Python, leur privateness est en fin de compte, une question de convention, pas force.

130
répondu xsl 2008-09-16 09:03:45

quand je suis arrivé de Java à Python, je détestais ceci. Ça m'a fait peur à la mort.

aujourd'Hui, c'est peut-être la seule chose j'aime le plus à propos de Python.

j'adore être sur une plateforme, où les gens se font confiance et ne se sentent pas obligés de construire des murs impénétrables autour de leur code. Dans les langages fortement encapsulés, si une API a un bug, et que vous avez compris ce qui ne va pas, vous peut encore être incapable de travailler autour de lui parce que la méthode nécessaire est privée. En Python, l'attitude est: "bien sûr". Si vous pensez comprendre la situation, peut-être même l'avez-vous lue, alors tout ce que nous pouvons dire, c'est: "bonne chance!".

rappelez-vous, l'encapsulation n'est même pas faiblement liée à la "sécurité", ou garder les enfants hors de la pelouse. C'est juste un autre modèle qui devrait être utilisé pour rendre une base de code plus facile à comprendre.

128
répondu Thomas Ahle 2017-10-08 07:15:50

L'expression utilisée est "nous sommes tous des adultes consentants ici". En préparant un simple underscore (don't expose) ou un double underscore (hide), vous dites à l'utilisateur de votre classe que vous voulez que le membre soit "privé" d'une manière ou d'une autre. Cependant, vous faites confiance à tous les autres pour se comporter de manière responsable et respecter cela, à moins qu'ils n'aient une raison impérieuse de ne pas le faire (par exemple débogueurs, code completion).

Si vous devez avoir quelque chose qui est privé, alors vous peut l'implémenter dans une extension (par exemple en C Pour CPython). Dans la plupart des cas, cependant, vous apprenez simplement la façon pythonique de faire les choses.

82
répondu Tony Meyer 2008-09-16 09:33:18

ce n'est pas comme si vous ne pouviez absolument pas contourner la confidentialité des membres dans n'importe quel langage (pointer arithmétique en C++, réflexions en .NET/Java).

le fait est que vous obtenez une erreur si vous essayez d'appeler la méthode privée par accident. Mais si tu veux te tirer une balle dans le pied, vas-y, fais-le.

Edit: vous n'essayez pas de sécuriser vos affaires par oo-encapsulation, n'est-ce pas?

30
répondu Maximilian 2008-09-16 09:04:57

un comportement similaire existe lorsque les noms d'attribut de module commencent par un simple underscore (par exemple _foo).

Les attributs du Module

nommés comme tels ne seront pas copiés dans un module d'importation lorsqu'on utilise la méthode from* , p.ex.:

from bar import *

cependant, il s'agit d'une convention et non d'une contrainte linguistique. Ce ne sont pas des attributs privés; ils peuvent être référencés et manipulés par n'importe quel importateur. Certains soutiennent qu'à cause de cela, Python ne peut pas implémenter la vraie encapsulation.

12
répondu Ross 2008-09-17 04:29:45

c'est juste un de ces choix de langage. Dans une certaine mesure, elles sont justifiées. Ils font en sorte que vous devez aller assez loin hors de votre chemin pour tenter d'appeler la méthode, et si vous en avez vraiment besoin que mal, vous devez avoir une très bonne raison!

crochets de débogage et de test viennent à l'esprit comme des applications possibles, utilisées de manière responsable bien sûr.

12
répondu ctcherry 2017-10-08 07:14:31

la convention de nommage class.__stuff permet au programmeur de savoir qu'il n'est pas censé accéder à __stuff de l'extérieur. Le nom mangling rend peu probable que quelqu'un le fasse par accident.

C'est vrai, vous pouvez toujours travailler autour de cela, c'est encore plus facile que dans d'autres langues (ce que BTW vous permet aussi de faire), mais aucun programmeur Python ne le ferait s'il se souciait de l'encapsulation.

11
répondu Nickolay 2008-09-16 09:05:52

avec Python 3.4 c'est le comportement:

>>> 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

Note que les mutilations règles sont conçus principalement pour éviter les accidents; il est toujours possible d'accéder ou de modifier une variable qui est considéré comme privé. Cela peut même être utile dans des circonstances particulières, comme dans le débogueur.

même si la question Est ancienne, j'espère que mon petit morceau pourrait être utile.

3
répondu Alberto 2017-10-08 07:17:09

la préoccupation la plus importante concernant les méthodes et attributs privés est de dire aux développeurs de ne pas l'appeler en dehors de la classe et c'est l'encapsulation. on peut mal comprendre la sécurité de l'encapsulation. quand on utilise délibérément une syntaxe comme celle (ci-dessous) que vous avez mentionnée, vous ne voulez pas d'encapsulation.

obj._MyClass__myPrivateMethod()

j'ai migré de C# et au début c'était bizarre pour moi aussi mais après un certain temps j'en suis venu à l'idée que seule la façon dont les concepteurs de code Python pensez à la programmation orientée objet est différent.

0
répondu Afshin Amiri 2018-04-26 22:37:29