¿Alguien puede explicar el significado exacto de tener guiones bajos antes del nombre de un objeto en Python y la diferencia entre ambos?
Además, ¿ese significado permanece igual si el objeto en cuestión es una variable, una función, un método, etc.?
python
oop
naming-conventions
ivanleoncz
fuente
fuente
Respuestas:
Subrayado simple
Los nombres, en una clase, con un guión bajo principal son simplemente para indicar a otros programadores que el atributo o método está destinado a ser privado. Sin embargo, no se hace nada especial con el nombre en sí.
Para citar PEP-8 :
Doble subrayado (cambio de nombre)
De los documentos de Python :
Y una advertencia de la misma página:
Ejemplo
fuente
__
doble guión bajo como nombre de variable? comoa, __ = foo()
Excelentes respuestas hasta ahora, pero faltan algunas cositas. Un guión que conduce sola no es exactamente simplemente una convención: si se utiliza
from foobar import *
, y el módulofoobar
no define una__all__
lista, los nombres importados desde el módulo no se incluyen los que tienen un subrayado inicial. Digamos que es principalmente una convención, ya que este caso es un rincón bastante oscuro ;-).La convención que conduce-subrayado es ampliamente utilizado no sólo para los privados nombres, sino también por lo que C ++ llamaría protegidas queridos - por ejemplo, los nombres de los métodos que están destinados totalmente a ser anulado por las subclases (incluso los que tienen que ser reemplazado ya que en la clase base they
raise NotImplementedError
! -) son a menudo nombres con guión bajo y subrayado para indicar al código usando instancias de esa clase (o subclases) que dichos métodos no deben llamarse directamente.Por ejemplo, para hacer una cola segura para subprocesos con una disciplina de cola diferente a FIFO, uno importa Cola, subclases Queue.Queue y anula métodos como
_get
y_put
; El "código de cliente" nunca llama a esos métodos ("enganchar"), sino a los métodos públicos ("organizadores") comoput
yget
(esto se conoce como el patrón de diseño del Método de plantilla ; consulte, por ejemplo, aquí una presentación interesante basada en un video de una charla mía sobre el tema, con la adición de sinopsis de la transcripción).Editar: los enlaces de video en la descripción de las conversaciones ahora están rotos. Puedes encontrar los dos primeros videos aquí y aquí .
fuente
_var_name
o usarvar_name
+ excluyéndolo__all__
?__all__
siempre que desee que el módulo seafrom spam import *
amigable (incluso en el intérprete interactivo). Entonces, la mayoría de las veces, la respuesta es ambas ._
privado . Evidentemente estoy hablando de analogías, ya que nada es realmente privado en Python. Cuando el buceo en la semántica yo diría que podemos atar el_
que de Java protegida desde proctected "clases derivadas y / o dentro del mismo paquete" en los medios de Java. Reemplace el paquete con el módulo ya que PEP8 ya nos dice que_
no es solo una convención cuando se habla de*
importaciones y ahí lo tiene. Y definitivamente__
sería equivalente al privado de Java cuando se habla de identificadores dentro de una clase.__foo__
: esto es solo una convención, una forma para que el sistema Python use nombres que no entren en conflicto con los nombres de usuario._foo
: esto es solo una convención, una forma para que el programador indique que la variable es privada (lo que sea que eso signifique en Python).__foo
: esto tiene un significado real: el intérprete reemplaza este nombre por_classname__foo
una forma de garantizar que el nombre no se superponga con un nombre similar en otra clase.Ninguna otra forma de guiones bajos tiene significado en el mundo de Python.
No hay diferencia entre clase, variable, global, etc. en estas convenciones.
fuente
__foo
y curioso. ¿Cómo puede superponerse con nombres de métodos similares con otras clases? Quiero decir que todavía tiene que acceder a él comoinstance.__foo()
(si el intérprete no lo cambió), ¿verdad?from module import *
no importa objetos con prefijo de subrayado. Por lo tanto,_foo
es más que una simple convención.B
subclases claseA
, y ambas implementanfoo()
,B.foo()
anula el.foo()
heredado deA
. Una instancia deB
solo podrá accederB.foo()
, excepto a través desuper(B).foo()
.__dunder__
nombres, las invocaciones implícitas omiten el diccionario de instancias, por lo que quizás sea un poco más que una simple convención de nomenclatura en algunos casos (ver la sección de búsqueda de métodos especiales en el modelo de datos).._variable
es semiprivado y solo para convenciones.__variable
a menudo se considera incorrectamente superprivado, mientras que su significado real es solo cambiar el nombre para evitar el acceso accidental [1].__variable__
normalmente está reservado para métodos o variables integradasAún puede acceder a las
.__mangled
variables si lo desea desesperadamente. El doble subraya solo nombres, o renombra la variable a algo comoinstance._className__mangled
Ejemplo:
t._b es accesible porque solo está oculto por convención
t .__ a no se encuentra porque ya no existe debido al cambio de nombre
Al acceder
instance._className__variable
lugar de solo el doble nombre de subrayado, puede acceder al valor ocultofuente
Subrayado simple al principio:
Python no tiene métodos privados reales. En cambio, un guión bajo al comienzo de un método o nombre de atributo significa que no debe acceder a este método, porque no es parte de la API.
(Este fragmento de código se tomó del código fuente de django: django / forms / forms.py). En este código,
errors
es una propiedad pública, pero el método al que llama esta propiedad, _get_errors, es "privado", por lo que no debe acceder a ella.Dos guiones bajos al principio:
Esto causa mucha confusión. No debe usarse para crear un método privado. Debe usarse para evitar que una subclase anule su método o acceda accidentalmente. Veamos un ejemplo:
Salida:
Ahora cree una subclase B y personalice el método __test
La salida será ...
Como hemos visto, A.test () no llamó a los métodos B .__ test (), como podríamos esperar. Pero, de hecho, este es el comportamiento correcto para __. Los dos métodos llamados __test () se renombran automáticamente (mutilados) a _A__test () y _B__test (), por lo que no se anulan accidentalmente. Cuando crea un método que comienza con __ significa que no quiere que nadie pueda anularlo, y solo tiene la intención de acceder desde su propia clase.
Dos guiones bajos al principio y al final:
Cuando vemos un método como
__this__
, no lo llames. Este es un método que Python debe llamar, no tú. Vamos a ver:Siempre hay un operador o una función nativa que llama a estos métodos mágicos. A veces es solo un gancho que Python llama en situaciones específicas. Por ejemplo,
__init__()
se llama cuando se crea el objeto después de que__new__()
se llama para construir la instancia ...Tomemos un ejemplo ...
Para más detalles, consulte la guía PEP-8 . Para más métodos mágicos, vea este PDF .
fuente
A veces tienes lo que parece ser una tupla con un guión bajo como en
En este caso, lo que sucede es que _ () es un alias para una función de localización que opera en el texto para colocarlo en el idioma adecuado, etc., según la configuración regional. Por ejemplo, Sphinx hace esto, y encontrarás entre las importaciones
y en sphinx.locale, _ () se asigna como un alias de alguna función de localización.
fuente
Dado que muchas personas se están refiriendo a la charla de Raymond , lo haré un poco más fácil escribiendo lo que dijo:
Digamos que no mantiene una referencia local de
perimeter
inCircle
. Ahora, una clase derivadaTire
anula la implementación deperimeter
, sin tocararea
. Cuando llamaTire(5).area()
, en teoría todavía debería estar usandoCircle.perimeter
para el cálculo, pero en realidad está usandoTire.perimeter
, que no es el comportamiento previsto. Es por eso que necesitamos una referencia local en Circle.¿Pero por qué en
__perimeter
lugar de_perimeter
? Porque_perimeter
todavía le da a la clase derivada la oportunidad de anular:Los guiones bajos dobles tienen nombre de cambio, por lo que hay muy pocas posibilidades de que la referencia local en la clase principal se anule en la clase derivada. así " hace que sus subclases sean libres de anular cualquier método sin romper los otros ".
Si su clase no será heredada, o la anulación del método no interrumpe nada, entonces simplemente no la necesita
__double_leading_underscore
.fuente
Si uno realmente quiere hacer una variable de solo lectura, en mi humilde opinión, la mejor manera sería usar property () con solo getter pasado a ella. Con property () podemos tener un control completo sobre los datos.
Entiendo que OP hizo una pregunta un poco diferente, pero como encontré otra pregunta que preguntaba 'cómo configurar variables privadas' marcada como duplicada con esta, pensé en agregar esta información adicional aquí.
fuente
Accroding a https://dbader.org/blog/meaning-of-underscores-in-python
fuente
Grandes respuestas y todo es correcto. He proporcionado un ejemplo simple junto con una definición / significado simple.
Sentido:
some_variable --► es público, cualquiera puede ver esto.
_algunas_variables --► es público, cualquiera puede ver esto, pero es una convención indicar privado ... advirtiendo que Python no realiza ninguna aplicación.
__some_varaible --► Python reemplaza el nombre de la variable con _classname__some_varaible (AKA name mangling) y reduce / oculta su visibilidad y se parece más a la variable privada.
Solo para ser honesto aquí De acuerdo con la documentación de Python
El ejemplo:
fuente
Los guiones bajos únicos destacados son una convención. no hay diferencia desde el punto de vista del intérprete si los nombres comienzan con un guión bajo o no.
Doble ataque y de salida de subrayado se utilizan para una función de métodos, tales como
__init__
,__bool__
, etc.Los dobles guiones bajos sin contrapartes finales también son una convención, sin embargo, los métodos de clase serán destrozados por el intérprete. Para variables o nombres de funciones básicas no existe diferencia.
fuente
Su pregunta es buena, no se trata solo de métodos. Las funciones y los objetos en los módulos también suelen tener el prefijo subrayado, y pueden tener el prefijo dos.
Pero, por ejemplo, los nombres __double_underscore no están machacados por nombre en los módulos. Lo que sucede es que los nombres que comienzan con uno (o más) guiones bajos no se importan si importa todo desde un módulo (desde la importación del módulo *), ni los nombres se muestran en la ayuda (módulo).
fuente
Aquí hay un ejemplo ilustrativo simple sobre cómo las propiedades de subrayado doble pueden afectar una clase heredada. Entonces con la siguiente configuración:
si luego crea una instancia secundaria en la REPL de python, verá lo siguiente
Esto puede ser obvio para algunos, pero me tomó por sorpresa en un entorno mucho más complejo.
fuente
Las variables de instancia "privadas" a las que no se puede acceder, excepto desde el interior de un objeto, no existen en Python. Sin embargo, hay una convención que es seguida por la mayoría del código de Python: un nombre con un guión bajo (por ejemplo, _spam) debe tratarse como una parte no pública de la API (ya sea una función, un método o un miembro de datos) . Debe considerarse un detalle de implementación y estar sujeto a cambios sin previo aviso.
referencia https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references
fuente
Obtener los hechos de _ y __ es bastante fácil; Las otras respuestas las expresan bastante bien. El uso es mucho más difícil de determinar.
Así es como lo veo:
Debe usarse para indicar que una función no es para uso público como, por ejemplo, una API. Esto y la restricción de importación hacen que se comporte como
internal
en C #.Debe usarse para evitar la colisión de nombres en la jerarquía de herencia y para evitar la vinculación tardía. Al igual que privado en C #.
==>
Si desea indicar que algo no es para uso público, pero debe actuar como
protected
uso_
. Si desea indicar que algo no es para uso público, pero debe actuar comoprivate
uso__
.Esta es también una cita que me gusta mucho:
Pero el problema con eso es, en mi opinión, que si no hay un IDE que te advierta cuando anulas los métodos, encontrar el error puede llevarte un tiempo si anulas accidentalmente un método de una clase base.
fuente