¿Python tiene variables “privadas” en las clases?

Vengo del mundo Java y leo los patrones, recetas y modismos de Python 3 de Bruce Eckels.

Mientras lee sobre 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í.

Así 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") xs = "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 se desean variables en una clase a la que nadie fuera de la clase tiene acceso.

    ¿Por qué no se requiere en Python?

    Es cultural En Python, no escribes en las variables de instancia o clase de otras clases. En Java, nada le impide hacer lo mismo si realmente quiere hacerlo; después de todo, siempre puede editar la fuente de la clase para lograr el mismo efecto. Python deja esa simulación de seguridad y alienta a los progtwigdores a ser responsables. En la práctica, esto funciona muy bien.

    Si quiere emular variables privadas por alguna razón, siempre puede usar el prefijo __ de PEP 8 . Python maneja 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 __foo si está suficientemente determinado, al igual que puede evitar las protecciones de Java si trabaja en eso).

    Por la misma convención, el prefijo _ significa mantenerse alejado, incluso si no está técnicamente impedido de hacerlo . No juegas con las variables de otra clase que se parecen a __foo o _bar .

    Las variables privadas en Python son más o menos un hack: el intérprete renombra intencionalmente la variable.

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

    Ahora, si intenta 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 puede salirse con la suya fácilmente:

      >>>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 , también se puede acceder a este campo fuera de A.printVar() … después de todo, las funciones se crean para su reutilización, no hay un poder especial otorgado a las declaraciones internas.

    El juego es diferente cuando hay un comstackdor involucrado (la privacidad es un concepto de nivel de comstackdor ). Conoce la definición de clase con modificadores de control de acceso, por lo que puede producir errores si no se siguen las reglas en el momento de la comstackción

    Como lo mencionamos correctamente en muchos de los comentarios anteriores, no olvidemos el objective principal de los modificadores de acceso: ayudar a los usuarios de código a comprender qué se supone que debe cambiar y qué se supone que no debe hacerlo. Cuando ves un campo privado no te metes con eso. Así que es principalmente azúcar sintáctica que se logra fácilmente en Python por _ y __.

    “En java, nos han enseñado sobre variables públicas / privadas / protegidas”

    “¿Por qué no se requiere eso en python?”

    Por la misma razón, no se requiere en Java.

    Usted es libre de usar, o no usar private y protected .

    Como progtwigdor de Python y Java, descubrí que lo private y lo 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 usado private o protected .

    Por qué no?

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

    ¿Otros progtwigdores en mi equipo? Ellos tienen la fuente. ¿Qué significa protegido cuando pueden cambiarlo?

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

    ¿Clientela? Es la progtwigción de trabajo por contrato (en general). Los clientes (generalmente) poseen el código.

    Entonces, ¿de quién, precisamente, estoy protegiéndolo?

    Hay una variación de las 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)  in () ----> 1 x.__private_method() AttributeError: 'Test' object has no attribute '__private_method' 

    Hay algunas diferencias sutiles, pero para la progtwigción de la pureza ideológica, es lo suficientemente bueno.

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

    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 identificador que comience con dos guiones bajos. Esto es transparente para el progtwigdor, en su mayor parte, pero el efecto neto es que cualquier variable nombrada de esta manera puede usarse como variables privadas.

    Vea aquí para más sobre eso.

    En general, la implementación de Python de la orientación a objetos es un poco primitiva en comparación con otros lenguajes. Pero me gusta esto, en realidad. Es una implementación muy simple desde el punto de vista conceptual y encaja bien con el estilo dynamic del lenguaje.

    La única vez que utilizo variables privadas es cuando necesito hacer otras cosas cuando escribo o leo la variable y, como tal, necesito forzar el uso de un setter y / o get.

    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ó en desuso, tomó mucho más tiempo identificar todas las rutas de código que usaban esa función. Cuando se forzó el uso de setters y getters, se podría escribir una statement de depuración para identificar que se había llamado al método en desuso y la ruta del código que lo llama.

    Cuando se encuentra en un proyecto en el que cualquiera puede escribir una extensión, notificar a los usuarios sobre métodos obsoletos que desaparecerán en algunas versiones, por lo tanto, es vital para mantener la ruptura del módulo al mínimo después de las actualizaciones.

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

    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 limitados disponibles para el desarrollo, es por eso que algunos niveles de protección no son tan estrictos en python. Puede usar “__” en el miembro de la clase, funciona correctamente, pero no parece lo suficientemente bueno: cada acceso a dicho campo contiene estos caracteres.

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

    Python es una muy buena herramienta. Pero es un lenguaje OOP simplificado. Sintácticamente y conceptualmente simplificado. El objective principal de la existencia de Python es brindar a los desarrolladores la posibilidad de escribir código de fácil lectura con un alto nivel de abstracción de una manera muy rápida.

    Como se mencionó anteriormente, puede indicar que una variable o método es privado prefijándolo con un guión bajo. Si no cree que esto sea suficiente, siempre puede usar el decorador de property . Aquí hay 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 la bar está haciendo referencia al valor de retorno de la función de la bar lugar de a la variable en sí, y por lo tanto se puede acceder pero no se puede cambiar. Sin embargo, si alguien realmente quisiera, simplemente podría usar _bar y asignarle un nuevo valor. No hay una manera segura de evitar que alguien acceda a las variables y los métodos que desea ocultar, como se ha dicho en varias ocasiones. Sin embargo, usar la property es el mensaje más claro que puede enviar para que no se edite una variable. property también se puede usar para rutas de acceso más complejas de obtención / establecimiento / eliminación, como se explica aquí: https://docs.python.org/3/library/functions.html#property

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

    En Python3, si solo quieres “encapsular” los atributos de clase, como en Java, puedes hacer lo mismo de esta manera:

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

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

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

    En la práctica, Python3 ofuscará el nombre del atributo global. Volviendo esto como un atributo “privado”, como en Java. El nombre del atributo sigue siendo global, pero de forma inaccesible, como un atributo privado en otros idiomas.

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

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

    En Python, el guión bajo “_” se usa para indicar que un método o variable no se considera parte del api público de una clase y que esta parte del 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 nueva de esta clase.

    El subrayado doble “__” no significa una “variable privada”. Se usa para definir variables que son “de clase local” y que no pueden ser fácilmente ocultadas por las subclases. Maneja el nombre de las variables.

    Por 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 

    self .__ El nombre de foobar se transforma automáticamente en self._A__foobar en la clase A. En la clase B, se maneja a self._B__foobar. Por lo tanto, cada subclase puede definir su propia variable __foobar sin anular sus variables primarias. Pero nada le impide acceder a las variables que comienzan con guiones bajos. Sin embargo, la manipulación de nombres le impide llamar a estas variables / métodos de forma incidental.

    Recomiendo ver a Raymond Hettingers hablar “Pythons class development toolkit” de Pycon 2013 (debería estar disponible en Youtube), lo que da un buen ejemplo de por qué y cómo debería usar @property y “__” – variables de instancia.