¿Qué significa subrayado simple y doble antes del nombre de un objeto?

1292

¿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.?

ivanleoncz
fuente
2
Una gran respuesta corta de otro hilo: stackoverflow.com/a/8689983/911945
Anton Tarasenko

Respuestas:

1157

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 :

_single_leading_underscore: indicador débil de "uso interno". Por ejemplo from M import *, no importa objetos cuyo nombre comience con un guión bajo.

Doble subrayado (cambio de nombre)

De los documentos de Python :

Cualquier identificador de la forma __spam(al menos dos guiones bajos iniciales, como máximo un guión bajo final) se reemplaza textualmente por _classname__spam, donde classnamese elimina el nombre de la clase actual con guiones bajos subrayados. Este cambio se realiza sin tener en cuenta la posición sintáctica del identificador, por lo que se puede utilizar para definir una instancia privada de clase y variables de clase, métodos, variables almacenadas en globales e incluso variables almacenadas en instancias. privado a esta clase en instancias de otras clases.

Y una advertencia de la misma página:

El cambio de nombre está destinado a dar a las clases una manera fácil de definir variables y métodos de instancia "privados", sin tener que preocuparse por las variables de instancia definidas por clases derivadas, o por mucking con variables de instancia por código fuera de la clase. Tenga en cuenta que las reglas de destrucción están diseñadas principalmente para evitar accidentes; Todavía es posible que un alma determinada acceda o modifique una variable que se considera privada.

Ejemplo

>>> class MyClass():
...     def __init__(self):
...             self.__superprivate = "Hello"
...             self._semiprivate = ", world!"
...
>>> mc = MyClass()
>>> print mc.__superprivate
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: myClass instance has no attribute '__superprivate'
>>> print mc._semiprivate
, world!
>>> print mc.__dict__
{'_MyClass__superprivate': 'Hello', '_semiprivate': ', world!'}
Andrew Keeton
fuente
17
¿Qué pasa si hay un nombre de variable declarado con 2 guiones bajos que no está en la clase? Es solo una variable normal, ¿verdad?
Dhruv Ramani
55
¿Cuál es el significado de simplemente __doble guión bajo como nombre de variable? comoa, __ = foo()
AJ
104
Esta respuesta es extremadamente engañosa, ya que lleva al lector a creer que dunderscore se usa para hacer que los atributos de instancia sean "superprivados". Este no es el caso, como lo explica Raymond Hettinger, quien declara explícitamente que dunderscore se usa incorrectamente para marcar a los miembros como privados, mientras que fue diseñado para ser lo opuesto a privado.
Markus Meskanen
14
@MarkusMeskanen No estoy de acuerdo, la respuesta declara explícitamente el uso de un dunderscore para crear instancias de variables y métodos privados de clase. Mientras que el dunderscore fue diseñado para hacer que estos métodos y variables sean sobrescritos fácilmente por las subclases (haciéndolos públicos), el uso de un dunderscore preserva una instancia privada para su uso dentro de esa clase.
arewm
77
@MarkusMeskanen: la libertad es que las subclases usen los mismos nombres que la superclase sin golpear a la superclase; en otras palabras, los nombres de las superclases se vuelven privados para sí mismos.
Ethan Furman
311

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ódulo foobarno 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 _gety _put; El "código de cliente" nunca llama a esos métodos ("enganchar"), sino a los métodos públicos ("organizadores") como puty get(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í .

Alex Martelli
fuente
1
Entonces, ¿cómo decides si usar _var_nameo usar var_name+ excluyéndolo __all__?
endolito el
3
@endolith Use guiones bajos para indicar al lector de su código que probablemente no deberían usar esto (por ejemplo, porque podría cambiarlo en la versión 2.0, o incluso en la 1.1); use explícito __all__siempre que desee que el módulo sea from spam import *amigable (incluso en el intérprete interactivo). Entonces, la mayoría de las veces, la respuesta es ambas .
abarnert
@AlexMartelli ¿Esta norma relacionada con la importación se discute legalmente en algún lugar de los documentos o en otro lugar?
Vicrobot
1
Me gusta la analogía de C ++. En primer lugar, no me gusta cuando la gente llama al _ 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.
Marius Mucenicu
2
Si bien es una respuesta decente, también es muy auto promocional.
Desarrollador web híbrido
299

__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__foouna 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.

Ned Batchelder
fuente
66
Acabo de encontrar __fooy curioso. ¿Cómo puede superponerse con nombres de métodos similares con otras clases? Quiero decir que todavía tiene que acceder a él como instance.__foo()(si el intérprete no lo cambió), ¿verdad?
Bibhas Debnath
81
Este tipo afirma que from module import *no importa objetos con prefijo de subrayado. Por lo tanto, _fooes más que una simple convención.
dotancohen
44
@Bibhas: si la clase Bsubclases clase A, y ambas implementan foo(), B.foo()anula el.foo() heredado de A. Una instancia de Bsolo podrá acceder B.foo(), excepto a través de super(B).foo().
naught101
3
Para los __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).
wim
206

._variable es semiprivado y solo para convenciones

.__variablea 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 integradas

Aún puede acceder a las .__mangledvariables si lo desea desesperadamente. El doble subraya solo nombres, o renombra la variable a algo comoinstance._className__mangled

Ejemplo:

class Test(object):
    def __init__(self):
        self.__a = 'a'
        self._b = 'b'

>>> t = Test()
>>> t._b
'b'

t._b es accesible porque solo está oculto por convención

>>> t.__a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute '__a'

t .__ a no se encuentra porque ya no existe debido al cambio de nombre

>>> t._Test__a
'a'

Al acceder instance._className__variable lugar de solo el doble nombre de subrayado, puede acceder al valor oculto

NickCSE
fuente
pero ¿qué tal si "__a" fuera una variable de clase, entonces no puede acceder a ella incluso con las instrucciones de los documentos de Python ..
Vitaliy Terziev
¿Puede actualizar su respuesta con un ejemplo de subrayado doble con respecto a la herencia?
variable el
116

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.

class BaseForm(StrAndUnicode):

    def _get_errors(self):
        "Returns an ErrorDict for the data provided for the form"
        if self._errors is None:
            self.full_clean()
        return self._errors

    errors = property(_get_errors)

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

class A(object):
    def __test(self):
        print "I'm a test method in class A"

    def test(self):
        self.__test()

a = A()
a.test()
# a.__test() # This fails with an AttributeError
a._A__test() # Works! We can access the mangled name directly!

Salida:

$ python test.py
I'm test method in class A
I'm test method in class A

Ahora cree una subclase B y personalice el método __test

class B(A):
    def __test(self):
        print "I'm test method in class B"

b = B()
b.test()

La salida será ...

$ python test.py
I'm test method in class A

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:

>>> name = "test string"
>>> name.__len__()
11
>>> len(name)
11

>>> number = 10
>>> number.__add__(40)
50
>>> number + 50
60

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 ...

class FalseCalculator(object):

    def __init__(self, number):
        self.number = number

    def __add__(self, number):
        return self.number - number

    def __sub__(self, number):
        return self.number + number

number = FalseCalculator(20)
print number + 10      # 10
print number - 20      # 40

Para más detalles, consulte la guía PEP-8 . Para más métodos mágicos, vea este PDF .

PythonDev
fuente
1
Después de editar esta respuesta, prefiero stackoverflow.com/a/8689983/1048186
Josiah Yoder
¿Qué quiere decir con "Como hemos visto, A.test () no llamó a los métodos B .__ test ()" - ¿a dónde llamó a A.test ()?
variable el
18

A veces tienes lo que parece ser una tupla con un guión bajo como en

def foo(bar):
    return _('my_' + bar)

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

from sphinx.locale import l_, _

y en sphinx.locale, _ () se asigna como un alias de alguna función de localización.

Tim D
fuente
11

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:

La intención de los subrayados dobles no era sobre la privacidad. La intención era usarlo exactamente así

class Circle(object):

    def __init__(self, radius):
        self.radius = radius

    def area(self):
        p = self.__perimeter()
        r = p / math.pi / 2.0
        return math.pi * r ** 2.0

    def perimeter(self):
        return 2.0 * math.pi * self.radius

    __perimeter = perimeter  # local reference


class Tire(Circle):

    def perimeter(self):
        return Circle.perimeter(self) * 1.25

En realidad, es lo opuesto a la privacidad, se trata de libertad. Hace que sus subclases sean libres de anular cualquier método sin romper los otros .

Digamos que no mantiene una referencia local de perimeterin Circle. Ahora, una clase derivada Tireanula la implementación de perimeter, sin tocar area. Cuando llama Tire(5).area(), en teoría todavía debería estar usando Circle.perimeterpara el cálculo, pero en realidad está usando Tire.perimeter, que no es el comportamiento previsto. Es por eso que necesitamos una referencia local en Circle.

¿Pero por qué en __perimeterlugar de _perimeter? Porque _perimetertodavía le da a la clase derivada la oportunidad de anular:

class Tire(Circle):

    def perimeter(self):
        return Circle.perimeter(self) * 1.25

    _perimeter = perimeter

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.

laike9m
fuente
1
Gracias, la diapositiva no se mostró correctamente, así que terminé sin entender por qué mi código fallaba.
cgte
8

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.

class PrivateVarC(object):

    def get_x(self):
        pass

    def set_x(self, val):
        pass

    rwvar = property(get_p, set_p)  

    ronly = property(get_p) 

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í.

Dev Maha
fuente
8

Accroding a https://dbader.org/blog/meaning-of-underscores-in-python

  • Single Leading subrayado (_var) : convención de nomenclatura que indica que un nombre está destinado para uso interno. Por lo general, el intérprete de Python no lo aplica (excepto en las importaciones de comodines) y solo es una pista para el programador.
  • Single Trailing subrayado (var_) : utilizado por convención para evitar conflictos de nombres con palabras clave de Python.
  • Doble guión bajo (__ var) : desencadena el cambio de nombre cuando se usa en un contexto de clase. Aplicado por el intérprete de Python.
  • Doble guión inicial y final (__ var__) : Indica métodos especiales definidos por el lenguaje Python. Evite este esquema de nombres para sus propios atributos.
  • Subrayado simple (_) : a veces se utiliza como un nombre para variables temporales o insignificantes ("no me importa"). Además: El resultado de la última expresión en una REPL de Python.
Feuda
fuente
5

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

"Las variables de instancia" privadas "a las que no se puede acceder, excepto desde el interior de un objeto, no existen en Python"

El ejemplo:

class A():
    here="abc"
    _here="_abc"
    __here="__abc"


aObject=A()
print(aObject.here) 
print(aObject._here)
# now if we try to print __here then it will fail because it's not public variable 
#print(aObject.__here)
grepit
fuente
_ _some_varaible - .... y reduce / oculta su visibilidad y se parece más a una variable privada. No, el cambio de nombre es el punto, no oculta el método.
AMC
4

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.

SilentGhost
fuente
3

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).

u0b34a0f6ae
fuente
1
Además, los nombres que comienzan con uno o más guiones bajos que tienen dos o más guiones bajos se comportan como cualquier otro nombre nuevamente.
Bentley4
3

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:

class parent(object):
    __default = "parent"
    def __init__(self, name=None):
        self.default = name or self.__default

    @property
    def default(self):
        return self.__default

    @default.setter
    def default(self, value):
        self.__default = value


class child(parent):
    __default = "child"

si luego crea una instancia secundaria en la REPL de python, verá lo siguiente

child_a = child()
child_a.default            # 'parent'
child_a._child__default    # 'child'
child_a._parent__default   # 'parent'

child_b = child("orphan")
## this will show 
child_b.default            # 'orphan'
child_a._child__default    # 'child'
child_a._parent__default   # 'orphan'

Esto puede ser obvio para algunos, pero me tomó por sorpresa en un entorno mucho más complejo.

Bagazo
fuente
3

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

aptro
fuente
1
_ es mucho más similar a, por ejemplo, interno en C # que privado. El subrayado doble es mucho más similar al privado que el subrayado es privado, diría.
Ini
2

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 internalen 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 protecteduso _. Si desea indicar que algo no es para uso público, pero debe actuar como privateuso __.

Esta es también una cita que me gusta mucho:

El problema es que el autor de una clase puede pensar legítimamente "este atributo / nombre del método debe ser privado, solo accesible desde esta definición de clase" y usar la convención privada. Pero más adelante, un usuario de esa clase puede hacer una subclase que legítimamente necesita acceso a ese nombre. Entonces, o la superclase tiene que modificarse (lo que puede ser difícil o imposible), o el código de la subclase tiene que usar nombres destrozados manualmente (que es feo y frágil en el mejor de los casos).

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.

Invader
fuente