Vengo del mundo Java y leo los patrones, recetas y modismos de Python 3 de Bruce Eckels .
Mientras lee sobre 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 allí.
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, 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, nos han enseñado sobre variables públicas / privadas / protegidas. Esas palabras clave tienen sentido porque a veces quieres variables en una clase a las que nadie fuera de la clase tenga acceso.
¿Por qué no se requiere eso en Python?
Respuestas:
Es cultural. En Python, no escribes en la instancia de otras clases o variables de clase. En Java, nada le impide hacer lo mismo si realmente lo desea; después de todo, siempre puede editar el origen 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 algún motivo, siempre puede usar el
__
prefijo de PEP 8 . Python manipula los nombres de las variables__foo
para que no sean fácilmente visibles para el código fuera de la clase que las contiene (aunque puede evitarlo si está lo suficientemente determinado, al igual que puede evitar las protecciones de Java si trabaja en él) )Según la misma convención, el
_
prefijo significa mantenerse alejado incluso si técnicamente no se le impide hacerlo . No juegas con las variables de otra clase que parecen__foo
o_bar
.fuente
Las variables privadas en python son más o menos un truco: el intérprete renombra intencionalmente la variable.
Ahora, si intenta acceder
__var
fuera de la definición de clase, fallará:Pero puedes salirte con la tuya fácilmente:
Probablemente sepa que los métodos en OOP se invocan así:
x.printVar() => A.printVar(x)
si seA.printVar()
puede acceder a algún campox
, también se puede acceder a este campo fueraA.printVar()
... después de todo, las funciones se crean para la reutilización, no hay un poder especial para las declaraciones en el interior.El juego es diferente cuando hay un compilador involucrado (la privacidad es un concepto de nivel de compilador ). Conoce la definición de clase con modificadores de control de acceso, por lo que puede generar un error si las reglas no se siguen en tiempo de compilación
fuente
Como se menciona correctamente en muchos de los comentarios anteriores, no olvidemos el objetivo principal de los modificadores de acceso: ayudar a los usuarios del código a comprender qué se supone que debe cambiar y qué no. Cuando ves un campo privado, no te equivocas con él. Por lo tanto, es principalmente azúcar sintáctico lo que se logra fácilmente en Python con _ y __.
fuente
Hay una variación de variables privadas en la convención de subrayado.
Hay algunas diferencias sutiles, pero en aras de la pureza ideológica del patrón de programación, es lo suficientemente bueno.
Hay ejemplos de decoradores @private que implementan más estrechamente el concepto, pero YMMV. Podría decirse que también se podría escribir una definición de clase que use meta
fuente
__x
comoA
el compilador reescribe una variable dentro de la clase_A__x
, todavía no es completamente privada y aún se puede acceder a ella._A__x
, no la voy a tocar. Podría ser contagioso. Huiré muchísimo de eso."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 necesario en Java.
Eres libre de usar, o no usar
private
yprotected
.Como programador de Python y Java, he encontrado eso
private
yprotected
son conceptos de diseño muy, muy importantes. Sin embargo, como cuestión práctica, en decenas de miles de líneas de Java y Python, nunca he hecho acostumbradoprivate
oprotected
.Por qué no?
Aquí está mi pregunta "¿protegido de quién?"
¿Otros programadores en mi equipo? Ellos tienen la fuente. ¿Qué significa protegido cuando pueden cambiarlo?
¿Otros programadores en otros equipos? Trabajan para la misma empresa. Pueden, con una llamada telefónica, obtener la fuente.
¿Clientela? Es una programación de trabajo por contrato (en general). Los clientes (generalmente) poseen el código.
Entonces, ¿de quién, precisamente, lo estoy protegiendo?
fuente
Como se mencionó anteriormente, puede indicar que una variable o método es privado con el prefijo de subrayado. Si cree que esto no es suficiente, siempre puede usar el
property
decorador. Aquí hay un ejemplo:De esta manera, alguien o algo que hace referencia en
bar
realidad está haciendo referencia al valor de retorno de labar
función en lugar de la variable en sí, y por lo tanto se puede acceder pero no cambiarlo. Sin embargo, si alguien realmente quisiera, simplemente podría usarlo_bar
y asignarle un nuevo valor. No hay una forma segura de evitar que alguien acceda a las variables y métodos que desea ocultar, como se ha dicho repetidamente. Sin embargo, el usoproperty
es el mensaje más claro que puede enviar que una variable no se debe editar.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#propertyfuente
Python tiene soporte limitado para identificadores privados, a través de una función que antepone automáticamente el nombre de la clase a cualquier identificador que 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 usarse como variables privadas.
Ver aquí para más información sobre eso.
En general, la implementación de la orientación a objetos de Python es un poco primitiva en comparación con otros lenguajes. Pero disfruto esto, en realidad. Es una implementación muy simple desde el punto de vista conceptual y se adapta bien al estilo dinámico del lenguaje.
fuente
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.
Nuevamente, esto va a la cultura, como ya se dijo. He estado trabajando en proyectos donde leer y escribir variables de otras clases era gratuito 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 se forzó el uso de setters y getters, se pudo escribir fácilmente una declaración 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 está en un proyecto en el que cualquiera puede escribir una extensión, notificar a los usuarios sobre los métodos obsoletos que desaparecerán en algunas versiones es vital para mantener la rotura del módulo al mínimo en las actualizaciones.
Entonces 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, se vuelve imperativo cuando se realizan cambios en el núcleo que deben ser capturados por todas las extensiones que utilizan el código.
fuente
Lo siento muchachos por "resucitar" el hilo, pero espero que esto ayude a alguien:
En Python3 si solo quiere "encapsular" los atributos de la clase, como en Java, puede hacer lo mismo de esta manera:
Para crear una instancia de esto, haga lo siguiente:
Tenga en cuenta que:
print(ss.__s)
arrojará un error.En la práctica, Python3 ofuscará el nombre del atributo global. Convirtiendo 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 tengas miedo de eso. No importa. También hace el trabajo. ;)
fuente
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 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 de Python OOP no es perfecto, pequeño o rubí mucho más cercano al concepto puro de OOP. Incluso C # o Java están más cerca.
Python es muy buena herramienta. Pero es un lenguaje OOP simplificado. Simplificada sintácticamente y conceptualmente. 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.
fuente
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 necesita encapsular una variable miembro, puede hacerlo utilizando "@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 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 nueva de esta clase.
El doble guión bajo "__" no significa una "variable privada". Se usa para definir variables que son "clase local" y que no pueden ser fácilmente anuladas por subclases. Destroza el nombre de las variables.
Por ejemplo:
El nombre de self .__ foobar se desgarra automáticamente en self._A__foobar en la clase A. En la clase B se desgarra en self._B__foobar. Por lo tanto, cada subclase puede definir su propia variable __foobar sin anular sus variables principales. Pero nada le impide acceder a variables que comienzan con guiones bajos dobles. Sin embargo, el cambio de nombre le impide llamar a estas variables / métodos de manera incidental.
Recomiendo ver a Raymond Hettingers hablar sobre "Pythons class development toolkit" de Pycon 2013 (debería estar disponible en Youtube), que ofrece un buen ejemplo de por qué y cómo debe usar @property y "__" - variables de instancia.
fuente
@property
Forma parte de Python estándar o es específico de un IDE?property
función incorporada, que está disponible desde python 2.2En realidad, puedes simular un
C#
getter y setter usando este simple truco:Luego úsalo de manera similar como en
C#
:Simplemente declara una variable local estática en una función que desempeñará un rol get / set, ya que es la única forma de compartir una variable a través de métodos get y set, sin que sea global para una clase o archivo.
fuente