En caso de duda, déjelo en "público", es decir, no agregue nada para ocultar el nombre de su atributo. Si tienes una clase con algún valor interno, no te preocupes por eso. En lugar de escribir:
class Stack(object):
def __init__(self):
self.__storage = [] # Too uptight
def push(self, value):
self.__storage.append(value)
escribe esto por defecto:
class Stack(object):
def __init__(self):
self.storage = [] # No mangling
def push(self, value):
self.storage.append(value)
Esta es sin duda una forma controvertida de hacer las cosas. Los novatos de Python simplemente lo odian e incluso algunos viejos de Python desprecian este valor predeterminado, pero de todos modos es el predeterminado, por lo que realmente te recomiendo que lo sigas, incluso si te sientes incómodo.
Si realmente desea enviar el mensaje "¡No puedo tocar esto!" para sus usuarios, la forma habitual es anteponer la variable con un guión bajo. Esto es solo una convención, pero la gente lo entiende y tiene doble cuidado al tratar con tales cosas:
class Stack(object):
def __init__(self):
self._storage = [] # This is ok but pythonistas use it to be relaxed about it
def push(self, value):
self._storage.append(value)
Esto también puede ser útil para evitar conflictos entre nombres de propiedades y nombres de atributos:
class Person(object):
def __init__(self, name, age):
self.name = name
self._age = age if age >= 0 else 0
@property
def age(self):
return self._age
@age.setter
def age(self, age):
if age >= 0:
self._age = age
else:
self._age = 0
¿Qué pasa con el doble subrayado? Bueno, la magia de doble subrayado se usa principalmente para evitar la sobrecarga accidental de métodos y conflictos de nombres con los atributos de las superclases. . Puede ser muy útil si escribe una clase que se espera que se amplíe muchas veces.
Si desea utilizarlo para otros fines, puede hacerlo, pero no es ni habitual ni recomendable.
EDITAR : ¿Por qué es así? Bueno, el estilo habitual de Python no enfatiza que las cosas sean privadas, ¡al contrario! Hay muchas razones para eso, la mayoría de ellas controvertidas ... Veamos algunas de ellas.
Python tiene propiedades
La mayoría de los lenguajes orientados a objetos en la actualidad utilizan el enfoque opuesto: lo que no debe usarse no debe ser visible, por lo que los atributos deben ser privados. Teóricamente, esto produciría clases más manejables y menos acopladas, porque nadie cambiaría los valores dentro de los objetos de forma imprudente.
Sin embargo, no es tan sencillo. Por ejemplo, las clases de Java tienen muchos atributos y captadores que solo obtienen los valores y establecedores que solo establecen los valores. Necesita, digamos, siete líneas de código para declarar un solo atributo, lo que un programador de Python diría que es innecesariamente complejo. Además, en la práctica, simplemente escribe todo este código para obtener un campo público, ya que puedes cambiar su valor usando los getters y setters.
Entonces, ¿por qué seguir esta política de privacidad predeterminada? Simplemente haga públicos sus atributos de forma predeterminada. Por supuesto, esto es problemático en Java, porque si decide agregar alguna validación a su atributo, sería necesario que cambie todos
person.age = age;
en su código para, digamos,
person.setAge(age);
setAge()
siendo:
public void setAge(int age) {
if (age >= 0) {
this.age = age;
} else {
this.age = 0;
}
}
Entonces, en Java (y otros lenguajes), el valor predeterminado es usar getters y setters de todos modos, porque pueden ser molestos de escribir pero pueden ahorrarle mucho tiempo si se encuentra en la situación que he descrito.
Sin embargo, no es necesario que lo haga en Python, ya que Python tiene propiedades. Si tienes esta clase:
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
y luego decides validar las edades, no necesitas cambiar las person.age = age
partes de tu código. Simplemente agregue una propiedad (como se muestra a continuación)
class Person(object):
def __init__(self, name, age):
self.name = name
self._age = age if age >= 0 else 0
@property
def age(self):
return self._age
@age.setter
def age(self, age):
if age >= 0:
self._age = age
else:
self._age = 0
Si puede hacerlo y seguir utilizándolo person.age = age
, ¿por qué agregaría campos privados y captadores y definidores?
(Además, consulte Python no es Java y este artículo sobre los daños de usar getters y setters ).
Todo es visible de todos modos, y tratar de esconderse solo complica su trabajo
Incluso en idiomas donde hay atributos privados, puede acceder a ellos a través de algún tipo de biblioteca de reflexión / introspección. Y la gente lo hace mucho, en marcos y para resolver necesidades urgentes. El problema es que las bibliotecas de introspección son solo una forma difícil de hacer lo que podría hacer con los atributos públicos.
Dado que Python es un lenguaje muy dinámico, es contraproducente agregar esta carga a sus clases.
El problema es que no se puede ver, se requiere ver
Para un Pythonista, la encapsulación no es la incapacidad de ver el interior de las clases, sino la posibilidad de evitar mirarlo. Lo que quiero decir es que la encapsulación es la propiedad de un componente que permite su uso sin que el usuario se preocupe por los detalles internos. Si puede usar un componente sin preocuparse por su implementación, entonces está encapsulado (en opinión de un programador de Python).
Ahora, si escribió su clase de tal manera que pueda usarla sin tener que pensar en los detalles de implementación, no hay problema si lo desea. mirar dentro de la clase por alguna razón. El punto es: tu API debería ser buena y el resto son detalles.
Guido lo dijo
Bueno, esto no es controvertido: lo dijo, en realidad . (Busque "kimono abierto").
Esta es la cultura
Sí, hay algunas razones, pero ninguna razón crítica. Este es principalmente un aspecto cultural de la programación en Python. Francamente, también podría ser al revés, pero no es así. Además, podría preguntar fácilmente al revés: ¿por qué algunos lenguajes usan atributos privados de forma predeterminada? Por la misma razón principal que para la práctica de Python: porque es la cultura de estos lenguajes, y cada elección tiene ventajas y desventajas.
Dado que ya existe esta cultura, se recomienda seguirla. De lo contrario, los programadores de Python le molestarán y le pedirán que elimine el__
de su código cuando haga una pregunta en Stack Overflow :)
Primero: ¿Qué es el cambio de nombre?
La alteración de nombres se invoca cuando está en una definición de clase y usa
__any_name
o__any_name_
, es decir, dos (o más) guiones bajos iniciales y como máximo un guión bajo final.Y ahora:
El uso ostensible es evitar que los subclasificadores usen un atributo que usa la clase.
Un valor potencial es evitar las colisiones de nombres con los subclasificadores que desean anular el comportamiento, de modo que la funcionalidad de la clase principal siga funcionando como se esperaba. Sin embargo, el ejemplo en la documentación de Python no es sustituible por Liskov, y no me viene a la mente ningún ejemplo en el que lo haya encontrado útil.
Las desventajas son que aumenta la carga cognitiva para leer y comprender una base de código, y especialmente cuando se depura, donde se ve el nombre de subrayado doble en la fuente y un nombre alterado en el depurador.
Mi enfoque personal es evitarlo intencionalmente. Trabajo en una base de código muy grande. Los raros usos de la misma sobresalen como un pulgar dolorido y no parecen justificados.
Debe ser consciente de ello para saberlo cuando lo vea.
PEP 8
PEP 8 , la guía de estilo de la biblioteca estándar de Python, actualmente dice (abreviado):
¿Como funciona?
Si antepone dos guiones bajos (sin terminar los guiones bajos dobles) en una definición de clase, el nombre se alterará y un guión bajo seguido del nombre de la clase se antepondrá al objeto:
Tenga en cuenta que los nombres solo se alterarán cuando se analice la definición de la clase:
Además, aquellos que son nuevos en Python a veces tienen problemas para comprender lo que sucede cuando no pueden acceder manualmente a un nombre que ven definido en una definición de clase. Esta no es una razón sólida en contra, pero es algo a considerar si tiene una audiencia que está aprendiendo.
¿Un subrayado?
Cuando mi intención es que los usuarios mantengan sus manos fuera de un atributo, tiendo a usar solo un guión bajo, pero eso es porque en mi modelo mental, los subclasificadores tendrían acceso al nombre (que siempre tienen, ya que pueden detectar fácilmente el nombre destrozado de todos modos).
Si estuviera revisando el código que usa el
__
prefijo, preguntaría por qué están invocando la alteración de nombres y si no podrían hacerlo tan bien con un solo guión bajo, teniendo en cuenta que si los subclasificadores eligen los mismos nombres para la clase y class atributo habrá una colisión de nombres a pesar de esto.fuente
No diría que la práctica produce un mejor código. Los modificadores de visibilidad solo lo distraen de la tarea en cuestión y, como efecto secundario, obligan a que su interfaz se use como desea. En términos generales, hacer cumplir la visibilidad evita que los programadores estropeen las cosas si no han leído la documentación correctamente.
Una solución mucho mejor es la ruta que fomenta Python: sus clases y variables deben estar bien documentadas y su comportamiento debe ser claro. La fuente debe estar disponible. Esta es una forma mucho más extensible y confiable de escribir código.
Mi estrategia en Python es esta:
Sobre todo, debe quedar claro lo que hace todo. Documente si alguien más lo usará. Documentelo si quiere que sea útil dentro de un año.
Como nota al margen, en realidad debería optar por la protección en esos otros idiomas: nunca se sabe que su clase podría heredarse más adelante y para qué podría usarse. Lo mejor es proteger solo aquellas variables de las que está seguro que no pueden o no deben ser utilizadas por código externo.
fuente
No debe comenzar con datos privados y hacerlos públicos según sea necesario. Más bien, debe comenzar por descubrir la interfaz de su objeto. Es decir, debería comenzar por averiguar qué ve el mundo (las cosas públicas) y luego averiguar qué cosas privadas son necesarias para que eso suceda.
Otros lenguajes dificultan hacer privado lo que alguna vez fue público. Es decir, romperé mucho código si hago mi variable privada o protegida. Pero con las propiedades en Python, este no es el caso. Más bien, puedo mantener la misma interfaz incluso reorganizando los datos internos.
La diferencia entre _ y __ es que Python en realidad intenta hacer cumplir este último. Por supuesto, no se esfuerza mucho, pero lo hace difícil. Habiendo _ simplemente les dice a otros programadores cuál es la intención, son libres de ignorar bajo su propio riesgo. Pero ignorar esa regla a veces es útil. Los ejemplos incluyen depuración, piratería temporal y trabajar con código de terceros que no estaba destinado a usarse de la forma en que lo usa.
fuente
Ya hay muchas buenas respuestas a esto, pero voy a ofrecer otra. Esto también es en parte una respuesta a las personas que siguen diciendo que el doble subrayado no es privado (realmente lo es).
Si observa Java / C #, ambos tienen private / protected / public. Todos estos son construcciones en tiempo de compilación . Solo se aplican en el momento de la compilación. Si tuviera que usar la reflexión en Java / C #, podría acceder fácilmente al método privado.
Ahora, cada vez que llamas a una función en Python, estás usando inherentemente la reflexión. Estos fragmentos de código son los mismos en Python.
La sintaxis del "punto" es sólo azúcar sintáctica para el último fragmento de código. Principalmente porque usar getattr ya es feo con solo una llamada de función. Simplemente empeora a partir de ahí.
Entonces con eso, no puede haber una versión Java / C # de privado, ya que Python no compila el código. Java y C # no pueden verificar si una función es privada o pública en tiempo de ejecución, ya que esa información se ha ido (y no tiene conocimiento de dónde se llama a la función).
Ahora, con esa información, la alteración del nombre del guión bajo doble tiene más sentido para lograr la "privacidad". Ahora, cuando se llama a una función desde la instancia 'self' y se da cuenta de que comienza con '__', simplemente realiza el cambio de nombre allí mismo. Es simplemente más azúcar sintáctico. Ese azúcar sintáctico permite el equivalente de 'privado' en un lenguaje que solo usa la reflexión para el acceso de miembros de datos.
Descargo de responsabilidad: nunca escuché a nadie del desarrollo de Python decir algo como esto. La verdadera razón de la falta de "privado" es cultural, pero también notará que la mayoría de los lenguajes de secuencias de comandos / interpretados no tienen privado. Un privado estrictamente ejecutable no es práctico en nada excepto en tiempo de compilación.
fuente
Primero: ¿Por qué quiere ocultar sus datos? ¿Por qué es eso tan importante?
La mayoría de las veces no quieres hacerlo, pero lo haces porque otros lo están haciendo.
Si realmente realmente no quiere que las personas usen algo, agregue uno guión bajo delante. Eso es todo ... Los Pythonistas saben que las cosas con un guión bajo no están garantizadas para funcionar siempre y pueden cambiar sin que usted lo sepa.
Así es como vivimos y estamos de acuerdo con eso.
El uso de dos guiones bajos hará que su clase sea tan mala para la subclase que incluso usted no querrá trabajar de esa manera.
fuente
La respuesta elegida hace un buen trabajo al explicar cómo las propiedades eliminan la necesidad de atributos privados , pero también agregaría que las funciones a nivel de módulo eliminan la necesidad de métodos privados .
Si convierte un método en una función a nivel de módulo, elimina la oportunidad de que las subclases lo anulen. Mover alguna funcionalidad al nivel de módulo es más Pythonic que tratar de ocultar métodos con cambios de nombre.
fuente
El siguiente fragmento de código explicará todos los casos diferentes:
sin guión bajo (a)
imprimir todos los atributos válidos del objeto de prueba
Aquí, puede ver que el nombre de __a se ha cambiado a _Test__a para evitar que esta variable sea anulada por cualquiera de las subclases. Este concepto se conoce como "Cambio de nombres" en Python. Puede acceder a esto de esta manera:
De manera similar, en el caso de _a, la variable es solo para notificar al desarrollador que debe usarse como variable interna de esa clase, el intérprete de Python no hará nada incluso si accedes a ella, pero no es una buena práctica.
se puede acceder a una variable desde cualquier lugar, es como una variable de clase pública.
Espero que la respuesta te haya ayudado :)
fuente
A primera vista debería ser igual que para otros lenguajes (bajo "otros" me refiero a Java o C ++), pero no lo es.
En Java, hizo privadas todas las variables que no deberían ser accesibles desde el exterior. Al mismo tiempo, en Python no puede lograr esto ya que no hay "privacidad" (como dice uno de los principios de Python: "Todos somos adultos"). Entonces, el subrayado doble significa solo "Chicos, no utilicen este campo directamente". El mismo significado tiene un guión bajo, que al mismo tiempo no causa ningún dolor de cabeza cuando tienes que heredar de una clase considerada (solo un ejemplo de un posible problema causado por un guión bajo doble).
Por lo tanto, le recomiendo que utilice un guión bajo único de forma predeterminada para los miembros "privados".
fuente
"Si tiene dudas sobre si una variable debe ser privada o protegida, es mejor optar por la privada". - sí, lo mismo ocurre en Python.
Algunas respuestas aquí dicen sobre 'convenciones', pero no dan los enlaces a esas convenciones. La guía autorizada para Python, PEP 8 establece explícitamente:
La distinción entre público y privado, y la manipulación de nombres en Python se han considerado en otras respuestas. Desde el mismo enlace,
fuente