Question

Python nous donne la possibilité de créer des méthodes et des variables "privées" au sein d'une classe en ajoutant un double caractère de soulignement, comme ceci: __ myPrivateMethod () . Comment, alors, peut-on expliquer cela

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

Quel est le problème?!

Je vais expliquer un peu cela à ceux qui ne l'ont pas bien compris.

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

Ce que j'ai fait ici est de créer une classe avec une méthode publique et une méthode privée et de 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 va bien ici; nous ne pouvons pas l'appeler. C'est en fait 'privé'. En fait, ce n'est pas le cas. L'exécution de dir () sur l'objet révèle une nouvelle méthode magique que python crée de manière magique pour toutes vos méthodes "privées".

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

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

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

Voilà pour l'encapsulation, hein?

En tout cas, j'avais toujours entendu dire que Python ne supportait pas l'encapsulation, alors pourquoi même essayer? Qu'est-ce qui donne?

Était-ce utile?

La solution

Le nom d'embrouillage permet de s'assurer que les sous-classes ne remplacent pas accidentellement les méthodes et attributs privés de leurs superclasses. Il n'est pas conçu pour empêcher un 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, cela tombe en panne si deux classes différentes portent le même nom.

Autres conseils

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

Quand je suis arrivé de Java à Python pour la première fois, je détestais cela. Cela m'a fait très peur.

Aujourd'hui, cela pourrait bien être la seule chose que j'aime le plus à propos de Python.

J'aime être sur une plate-forme, où les gens se font confiance et ne ressentent pas le besoin de construire des murs impénétrables autour de leur code. Dans les langages fortement encapsulés, si une API comporte un bogue et que vous avez compris ce qui ne va pas, vous ne pourrez toujours pas le contourner car la méthode requise est privée. En Python, l’attitude est: "sûr". Si vous pensez que vous comprenez la situation, vous l’avez peut-être même lue, alors tout ce que nous pouvons dire est "bonne chance!".

N'oubliez pas que l'encapsulation n'a même pas de lien faible avec la "sécurité", ni d'empêcher les enfants de sortir de la pelouse. C’est un autre motif à utiliser pour rendre une base de code plus facile à comprendre.

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

  

Strictement parlant, les méthodes privées sont   accessible en dehors de leur classe, juste   pas facilement accessible. Rien dans   Python est vraiment privé; intérieurement,   les noms des méthodes privées et   les attributs sont mutilés et démêlés   à la volée pour les faire paraître   inaccessibles par leurs prénoms. Vous   peut accéder à la méthode __parse du   Classe MP3FileInfo par le nom   _MP3FileInfo__parse. Reconnaissez que c'est intéressant, puis promettez de   ne le faites jamais, jamais dans du code réel.   Les méthodes privées sont privées pour un   raison, mais comme beaucoup d'autres choses dans   Python, leur caractère privé est   finalement une question de convention, pas   force.

L’expression couramment utilisée est "nous sommes tous des adultes consentants ici". En ajoutant un simple soulignement (ne pas exposer) ou un double soulignement (masquer), vous indiquez à l'utilisateur de votre classe que vous souhaitez que le membre soit «privé» d'une manière ou d'une autre. Cependant, vous faites confiance à tous les autres pour qu'ils se comportent de manière responsable et respectent ce principe, à moins qu'ils n'aient une raison impérieuse de ne pas le faire (par exemple, les débogueurs, la complétion de code).

Si vous devez vraiment avoir quelque chose de privé, vous pouvez l’implémenter dans une extension (par exemple, en C pour CPython). Cependant, dans la plupart des cas, vous apprenez simplement comment faire les choses en Pythonic.

Ce n'est pas comme si vous ne pouviez absolument pas contourner le caractère privé des membres dans toutes les langues (arithmétique de pointeur en C ++, Reflections 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 vous voulez vous tirer une balle dans le pied, allez-y, faites-le.

Modifier: vous n'essayez pas de sécuriser vos données par OO-encapsulation, n'est-ce pas?

La convention de dénomination de la classe . indique au programmeur qu'il n'est pas censé accéder à __ article de l'extérieur. Le nom mangling rend improbable que quelqu'un le fasse par accident.

Certes, vous pouvez toujours contourner cela, c'est encore plus facile que dans d'autres langages (BTW vous le permet également), mais aucun programmeur Python ne le ferait s'il se souciait de l'encapsulation.

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

Les attributs de module nommés en tant que tels ne seront pas copiés dans un module d'importation lors de l'utilisation de la méthode à partir de * , par exemple:

.
from bar import *

Cependant, il s’agit d’une convention et non d’une contrainte de langage. Ce ne sont pas des attributs privés; ils peuvent être référencés et manipulés par n'importe quel importateur. Certains font valoir que, pour cette raison, Python ne peut pas implémenter la véritable encapsulation.

Ce n’est qu’un de ces choix de conception linguistique. À un certain niveau, ils sont justifiés. Ils font en sorte que vous devez aller assez loin pour essayer d'appeler la méthode, et si vous en avez vraiment besoin, vous devez avoir une très bonne raison!

Les points d'ancrage et les tests nous viennent à l'esprit en tant qu'applications possibles, utilisées de manière responsable, bien sûr.

Avec Python 3.4, il s’agit du comportement suivant:

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

  

Notez que les règles de sécurité sont principalement conçues pour éviter les accidents. il est toujours possible d'accéder à une variable considérée comme privée et de la modifier . Cela peut même être utile dans certaines circonstances, comme dans le débogueur.

Même si la question est ancienne, j'espère que mon extrait de code pourrait être utile.

Le problème le plus important concernant les méthodes et attributs privés est de dire aux développeurs de ne pas l'appeler en dehors de la classe. Il s'agit d'une encapsulation. on peut mal comprendre la sécurité de l’encapsulation. quand on utilise délibérément la syntaxe comme celle 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 moment, j’ai eu l’idée que seule la façon dont les concepteurs de code Python envisagent la POO est différente.

  

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

Si je comprends bien, ils ne peuvent pas être privés. Comment faire respecter la vie privée?

La réponse évidente est "Les membres privés ne sont accessibles que par self ", mais cela ne fonctionnerait pas - self n'est pas spécial en Python, il est rien de plus qu'un nom couramment utilisé pour le premier paramètre d'une fonction.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top