Pregunta

Python nos brinda la capacidad de crear métodos y variables 'privados' dentro de una clase anteponiendo guiones bajos dobles al nombre, como este: __myPrivateMethod().¿Cómo se puede entonces explicar esto?

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

¡¿Cual es el trato?!

Explicaré esto un poco para aquellos que no lo entendieron del todo.

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

Lo que hice allí fue crear una clase con un método público y un método privado y crear una instancia.

A continuación, llamo a su método público.

>>> obj.myPublicMethod()
public method

A continuación, intento llamar a su método privado.

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

Todo se ve bien aquí;no podemos llamarlo.De hecho, es "privado".Bueno, en realidad no lo es.Correr directorio() en el objeto revela un nuevo método mágico que Python crea mágicamente para todos sus métodos "privados".

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

El nombre de este nuevo método siempre es un guión bajo, seguido del nombre de la clase, seguido del nombre del método.

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

Hasta aquí la encapsulación, ¿eh?

En cualquier caso, siempre escuché que Python no admite la encapsulación, así que ¿por qué intentarlo?¿Lo que da?

¿Fue útil?

Solución

La codificación de nombres se utiliza para garantizar que las subclases no anulen accidentalmente los métodos y atributos privados de sus superclases.No está diseñado para impedir el acceso deliberado desde el exterior.

Por ejemplo:

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

Por supuesto, se estropea si dos clases diferentes tienen el mismo nombre.

Otros consejos

Ejemplo de función privada

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

Cuando vine por primera vez de Java a Python, odiado este.Me dio un susto de muerte.

Hoy podría ser sólo la única cosa me gusta más sobre Python.

Me encanta estar en una plataforma donde las personas confían entre sí y no sienten que necesitan construir muros impenetrables alrededor de su código.En lenguajes fuertemente encapsulados, si una API tiene un error y usted ha descubierto qué es lo que falla, es posible que aún no pueda solucionarlo porque el método necesario es privado.En Python la actitud es:"seguro".Si crees que entiendes la situación, tal vez incluso la hayas leído, entonces lo único que podemos decir es "¡buena suerte!".

Recuerde, la encapsulación no está ni siquiera débilmente relacionada con la "seguridad" o con mantener a los niños fuera del césped.Es solo otro patrón que debería usarse para hacer que una base de código sea más fácil de entender.

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

Hablando estrictamente, los métodos privados son accesibles fuera de su clase, pero no son fácilmente accesibles.Nada en Python es verdaderamente privado;Internamente, los nombres de los métodos y atributos privados están destrozados y sin tirar sobre la mosca para que parezcan inaccesibles por sus nombres de pila.Puede acceder al método __parse de la clase mp3FileInfo por el nombre _mp3fileInfo__parse.Reconoce que esto es interesante, luego promete nunca hacerlo en código real.Los métodos privados son privados por una razón, pero como muchas otras cosas en Python, su privacidad es, en última instancia, una cuestión de convención, no de fuerza.

La frase comúnmente utilizada es "aquí todos somos adultos que consienten".Al anteponer un guión bajo simple (no exponer) o un guión bajo doble (ocultar), le estás diciendo al usuario de tu clase que deseas que el miembro sea "privado" de alguna manera.Sin embargo, usted confía en que todos los demás se comportarán de manera responsable y lo respetarán, a menos que tengan una razón de peso para no hacerlo (p. ej.depuradores, finalización de código).

Si realmente necesitas tener algo que sea privado, entonces puedes implementarlo en una extensión (p. ej.en C para CPython).Sin embargo, en la mayoría de los casos, simplemente aprendes la forma Pythonic de hacer las cosas.

No es que no puedas evitar la privacidad de los miembros en ningún idioma (aritmética de punteros en C++, Reflections en .NET/Java).

El punto es que obtienes un error si intentas llamar al método privado por accidente.Pero si quieres pegarte un tiro en el pie, hazlo.

Editar:No intentas proteger tus cosas mediante encapsulación OO, ¿verdad?

El class.__stuff la convención de nomenclatura le permite al programador saber que no debe acceder __stuff desde afuera.La alteración del nombre hace que sea poco probable que alguien lo haga por accidente.

Es cierto que aún puedes solucionar esto, es incluso más fácil que en otros lenguajes (que, por cierto, también te permiten hacer esto), pero ningún programador de Python haría esto si le preocupa la encapsulación.

Existe un comportamiento similar cuando los nombres de los atributos del módulo comienzan con un solo guión bajo (p. ej._foo).

Los atributos del módulo nombrados como tales no se copiarán en un módulo de importación cuando se utilice el from* método, por ejemplo:

from bar import *

Sin embargo, esto es una convención y no una restricción del idioma.Estos no son atributos privados;cualquier importador puede consultarlos y manipularlos.Algunos argumentan que debido a esto, Python no puede implementar una verdadera encapsulación.

Es sólo una de esas opciones de diseño de lenguaje.En cierto nivel están justificados.Hacen que tengas que esforzarte bastante para intentar llamar al método, y si realmente lo necesitas tanto, ¡debes tener una muy buena razón!

Los ganchos de depuración y las pruebas me vienen a la mente como posibles aplicaciones, utilizadas de manera responsable, por supuesto.

Con Python 3.4 este es el comportamiento:

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

Tenga en cuenta que las reglas de manipulación están diseñadas principalmente para evitar accidentes; todavía es posible acceder o modificar una variable que se considera privada. Esto incluso puede resultar útil en circunstancias especiales, como en el depurador.

Incluso si la pregunta es antigua, espero que mi fragmento pueda ser útil.

La preocupación más importante sobre los métodos y atributos privados es decirles a los desarrolladores que no los llamen fuera de la clase y esto es encapsulación.uno puede malinterpretar la seguridad de la encapsulación.cuando uno usa deliberadamente una sintaxis como la que mencionaste (a continuación), no deseas la encapsulación.

obj._MyClass__myPrivateMethod()

Migré de C# y al principio también fue extraño para mí, pero después de un tiempo llegué a la idea de que solo la forma en que los diseñadores de código Python piensan sobre la programación orientada a objetos es diferente.

¿Por qué los métodos "privados" de Python no son realmente privados?

Según tengo entendido, ellos no poder ser privado.¿Cómo se podría hacer cumplir la privacidad?

La respuesta obvia es "solo se puede acceder a miembros privados a través de self", pero eso no funcionaría - self no es especial en Python, no es más que un nombre de uso común para el primer parámetro de una función.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top