¿Python tiene variables "privadas" en las clases?


Vengo del mundo Java y estoy leyendo los patrones, Recetas y Modismos de Python 3 de Bruce Eckels .

Mientras lee acerca de las clases, continúa diciendo que en Python no hay necesidad de declarar variables de instancia. Solo los usas en el constructor, y boom, están ahí.

Por ejemplo:

class Simple:
    def __init__(self, s):
        print("inside the simple constructor")
        self.s = s

    def show(self):
        print(self.s)

    def showMsg(self, msg):
        print(msg + ':', self.show())

Si eso es cierto, entonces cualquier objeto de la clase Simple puede cambiar el valor de la variable s fuera de la clase.

Por ejemplo:

if __name__ == "__main__":
    x = Simple("constructor argument")
    x.s = "test15" # this changes the value
    x.show()
    x.showMsg("A message")

En Java, se nos ha enseñado sobre variables públicas/privadas/protegidas. Esas palabras clave tienen sentido porque a veces desea variables en una clase a la que nadie fuera de la clase tiene acceso.

¿Por qué no se requiere eso en Python?

Author: Zags, 2009-10-29

11 answers

Es cultural. En Python, no escribes en instancias o variables de clase de otras clases. En Java, nada te impide hacer lo mismo si realmente quieres - después de todo, siempre puedes editar la fuente de la clase para lograr el mismo efecto. Python elimina esa pretensión de seguridad y alienta a los programadores a ser responsables. En la práctica, esto funciona muy bien.

Si desea emular variables privadas por alguna razón, siempre puede usar el prefijo __ de PEP 8. Python modifica los nombres de variables como __foo para que no sean fácilmente visibles para el código fuera de la clase que las contiene (aunque puede sortearlo si está lo suficientemente determinado, al igual que puede sortear las protecciones de Java si trabaja en ello).

Por la misma convención, el prefijo _ significa manténgase alejado incluso si técnicamente no se le impide hacerlo. No juegas con las variables de otra clase que parece __foo o _bar.

 780
Author: Kirk Strauser,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-02 05:16:58

Las variables privadas en python son más o menos un truco: el intérprete cambia intencionalmente el nombre de la variable.

class A:
    def __init__(self):
        self.__var = 123
    def printVar(self):
        print self.__var

Ahora, si intentas acceder a __var fuera de la definición de la clase, fallará:

 >>>x = A()
 >>>x.__var # this will return error: "A has no attribute __var"

 >>>x.printVar() # this gives back 123

Pero puedes salirte fácilmente con la tuya:

 >>>x.__dict__ # this will show everything that is contained in object x
               # which in this case is something like {'_A__var' : 123}

 >>>x._A__var = 456 # you now know the masked name of private variables
 >>>x.printVar() # this gives back 456

Probablemente sepa que los métodos en OOP se invocan así: x.printVar() => A.printVar(x), si A.printVar() puede acceder a algún campo en x, este campo también se puede acceder fuera A.printVar()...después de todo, las funciones se crean para su reutilización, no hay ningún poder especial dado a las declaraciones en el interior.

El juego es diferente cuando hay un compilador involucrado (la privacidad es un concepto de nivel de compilador). Sabe acerca de la definición de clase con modificadores de control de acceso para que pueda error si las reglas no se están siguiendo en tiempo de compilación

 109
Author: watashiSHUN,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-26 06:53:13

Como se mencionó correctamente en muchos de los comentarios anteriores, no olvidemos el objetivo principal de los Modificadores de Acceso: Ayudar a los usuarios de código a comprender lo que se supone que debe cambiar y lo que se supone que no. Cuando ves un campo privado no te metes con él. Así que es sobre todo azúcar sintáctica que se logra fácilmente en Python por el _ y __.

 19
Author: Ardavan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-17 05:17:25

"En Java, se nos ha enseñado sobre variables públicas / privadas / protegidas"

"¿Por qué no se requiere eso en python?"

Por la misma razón no es requerido en Java.

Eres libre de usar {o no usar private y protected.

Como programador de Python y Java, he encontrado que private y protected son conceptos de diseño muy, muy importantes. Pero como cuestión práctica, en decenas de miles de líneas de Java y Python, nunca he realmente usado private o protected.

¿Por qué no?

Aquí está mi pregunta "¿protegido de quién?"

¿Otros programadores de mi equipo? Tienen la fuente. ¿Qué significa protegido cuando pueden cambiarlo?

Otros programadores en otros equipos? Trabajan para la misma empresa. Pueden get con una llamada telefónica get obtener la fuente.

Clientes? Es programación de trabajo por contrato (generalmente). Los clientes (generalmente) poseen el código.

Entonces, ¿quién precisely precisamente protecting lo estoy protegiendo ¿de?

Correcto. El sociópata esquizofrénico que se negó a leer los bloques de comentarios API.

 14
Author: S.Lott,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-29 02:28:33

Hay una variación de variables privadas en la convención de subrayado.

In [5]: class Test(object):
   ...:     def __private_method(self):
   ...:         return "Boo"
   ...:     def public_method(self):
   ...:         return self.__private_method()
   ...:     

In [6]: x = Test()

In [7]: x.public_method()
Out[7]: 'Boo'

In [8]: x.__private_method()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-8-fa17ce05d8bc> in <module>()
----> 1 x.__private_method()

AttributeError: 'Test' object has no attribute '__private_method'

Hay algunas diferencias sutiles, pero por el bien de la pureza ideológica del patrón de programación, es suficiente.

Hay ejemplos por ahí de @decoradores privados que implementan más de cerca el concepto, pero YMMV. Podría decirse que también se podría escribir una definición de clase que utiliza meta

 10
Author: Shayne,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-16 12:41:34

Python tiene soporte limitado para identificadores privados, a través de una característica que automáticamente antepone el nombre de la clase a cualquier identificadorque comience con dos guiones bajos. Esto es transparente para el programador, en su mayor parte, pero el efecto neto es que cualquier variable nombrada de esta manera puede ser utilizada como variables privadas.

Ver aquí para más sobre eso.

En general, la implementación de Python de orientación a objetos es un poco primitiva en comparación con otros lenguajes. Pero disfruto esto, en realidad. Es una implementación muy simple conceptualmente y encaja bien con el estilo dinámico del lenguaje.

 8
Author: Dan Olson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-10-29 01:59:36

La única vez que uso variables privadas es cuando necesito hacer otras cosas al escribir o leer desde la variable y como tal necesito forzar el uso de un setter y/o getter.

De nuevo esto va a la cultura, como ya se ha dicho. He estado trabajando en proyectos donde leer y escribir otras variables de clases era gratis para todos. Cuando una implementación quedó obsoleta, tomó mucho más tiempo identificar todas las rutas de código que usaban esa función. Cuando el uso de setters y getters fue forzado, una sentencia debug podría escribirse fácilmente para identificar que el método obsoleto ha sido llamado y la ruta de código que lo llama.

Cuando estás en un proyecto donde cualquiera puede escribir una extensión, notificar a los usuarios sobre métodos obsoletos que van a desaparecer en unas pocas versiones, por lo tanto, es vital para mantener la rotura del módulo al mínimo en las actualizaciones.

Así que mi respuesta es; si usted y sus colegas mantienen un conjunto de código simple, entonces proteger las variables de clase no siempre es necesario. Si está escribiendo un sistema extensible, entonces se vuelve imperativo cuando se realizan cambios en el núcleo que deben ser capturados por todas las extensiones que usan el código.

 7
Author: BlueEagle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-01 09:28:42

Los conceptos privados y protegidos son muy importantes. Pero python-solo una herramienta para la creación de prototipos y el desarrollo rápido con recursos restringidos disponibles para el desarrollo, es por eso que algunos de los niveles de protección no son tan estrictos seguidos en python. Puede usar "_ _ " en miembro de la clase, funciona correctamente , pero no se ve lo suficientemente bien-cada acceso a dicho campo contiene estos caracteres.

Además, se puede notar que el concepto de python OOP no es perfecto, smaltalk o ruby mucho más cercano a la pure OOP concepto. Incluso C# o Java están más cerca.

Python es una herramienta muy buena. Pero se simplifica el lenguaje OOP. Sintáctica y conceptualmente simplificada. El objetivo principal de la existencia de python es brindar a los desarrolladores la posibilidad de escribir código fácil de leer con un alto nivel de abstracción de una manera muy rápida.

 6
Author: user711294,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-17 06:00:14

Como se mencionó anteriormente, puede indicar que una variable o método es privado prefijándolo con un guion bajo. Si no sientes que esto es suficiente, siempre puedes usar el decorador property. He aquí un ejemplo:

class Foo:

    def __init__(self, bar):
        self._bar = bar

    @property
    def bar(self):
        """Getter for '_bar'."""
        return self._bar

De esta manera, alguien o algo que hace referencia a bar en realidad está haciendo referencia al valor devuelto de la función bar en lugar de la variable en sí, y por lo tanto se puede acceder a ella pero no cambiarla. Sin embargo, si alguien realmente quería, simplemente podía usar _bar y asignarle un nuevo valor. No hay una manera segura de evitar que alguien acceda a variables y métodos que desea ocultar, como se ha dicho repetidamente. Sin embargo, usar property es el mensaje más claro que puede enviar para que una variable no se edite. property también se puede usar para rutas de acceso getter/setter/deleter más complejas, como se explica aquí: https://docs.python.org/3/library/functions.html#property

 5
Author: Isaac Saffold,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-03 14:24:47

Lo siento chicos por "resucitar" el hilo, pero, espero que esto ayude a alguien:

En Python3 si solo quieres "encapsular" los atributos de la clase, como en Java, puedes hacer lo mismo así:

class Simple:
    def __init__(self, str):
        print("inside the simple constructor")
        self.__s = str

    def show(self):
        print(self.__s)

    def showMsg(self, msg):
        print(msg + ':', self.show())

Para instanciar esto haga:

ss = Simple("lol")
ss.show()

Tenga en cuenta que: print(ss.__s) lanzará un error.

En la práctica, Python3 ofusca el nombre del atributo global. Convertir esto como un atributo "privado", como en Java. El nombre del atributo sigue siendo global, pero en un inaccesible, como un atributo privado en otros idiomas.

Pero no le tengas miedo. No importa. Hace el trabajo también. ;)

 3
Author: Ferrarezi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-21 16:06:06

Python no tiene ninguna variable privada como C++ o Java. También puede acceder a cualquier variable de miembro en cualquier momento si lo desea. Sin embargo, no necesita variables privadas en Python, porque en Python no es malo exponer las variables de los miembros de sus clases. Si necesita encapsular una variable miembro, puede hacerlo utilizando "@property" más adelante sin romper el código de cliente existente.

En python el guion bajo simple " _ " se usa para indicar, que un método o variable no se considera como parte de la api pública de una clase y que esta parte de la api podría cambiar entre diferentes versiones. Puede usar estos métodos / variables, pero su código podría romperse, si usa una versión más reciente de esta clase.

El doble guion bajo "__" no significa una "variable privada". Se usa para definir variables que son "clase local" y que no pueden ser fácilmente sobreidden por subclases. Cambia el nombre de las variables.

Para ejemplo:

class A(object):
    def __init__(self):
        self.__foobar = None # will be automatically mangled to self._A__foobar

class B(A):
    def __init__(self):
        self.__foobar = 1 # will be automatically mangled to self._B__foobar

Auto._el nombre de _foobar se convierte automáticamente en uno mismo._ A _ _ foobar en clase A. En clase B está destrozado a sí mismo._B_ _ foobar. Así que cada subclase puede definir su propia variable __foobar sin primordial de sus padres variable(s). Pero nada le impide acceder a las variables que comienzan con guiones bajos dobles. Sin embargo, la alteración de nombres le impide llamar a estas variables /métodos incidentalmente.

Recomiendo encarecidamente ver Raymond Hettingers hablar " Pitones class development toolkit " de Pycon 2013 (debería estar disponible en Youtube), lo que da un buen ejemplo de por qué y cómo debe usar las variables @property y "__"-instance.

 -1
Author: Hatatister,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-26 22:23:39