¿Cuál es el significado del subrayado simple y doble antes del nombre de un objeto?

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

preguntado el 19 de agosto de 09 a las 14:08

Una gran respuesta corta de otro hilo: stackoverflow.com/a/8689983/911945 -

17 Respuestas

Guión bajo único

Los nombres, en una clase, con un guión bajo al principio 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". P.ej from M import * no importa objetos cuyo nombre comience con un guión bajo.

Doble subrayado (cambio de nombre)

Desde los documentos de Python:

Cualquier identificador del formulario __spam (al menos dos guiones bajos iniciales, como máximo un guión bajo final) se reemplaza textualmente con _classname__spam, Donde classname es el nombre de la clase actual con los subrayados iniciales eliminados. Esta alteración se realiza sin tener en cuenta la posición sintáctica del identificador, por lo que se puede utilizar para definir 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:

La alteración de nombres está destinada 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 manipular variables de instancia por código fuera de la clase. Tenga en cuenta que las reglas de manipulació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!'}

Respondido 18 Oct 18, 12:10

¿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

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". Esto es no el caso, como se explica aquí por 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

@MarkusMeskanen No estoy de acuerdo, la respuesta establece explícitamente el uso de un dunderscore para crear instancias de variables y métodos privados de clase. Si bien el dunderscore fue diseñado para hacer que estos métodos y variables se sobrescriban fácilmente por subclases (haciéndolos públicos), el uso de dunderscore conserva una instancia privada para su uso dentro de esa clase. - arewm

@MarkusMeskanen: La libertad es que las subclases usen los mismos nombres que la superclase sin golpear a la superclase; en otras palabras, los nombres dunder de las superclases se vuelven privados para sí mismos. - ethan furman

Para un guión bajo, la respuesta dice "no se hace nada especial con el nombre en sí", pero luego continúa diciendo from M import * lo trata de manera diferente ... así que algo especial is hecho... - flujo2k

Excelentes respuestas hasta ahora, pero faltan algunas cositas. Un solo subrayado inicial no es exactamente a unos una convención: si usas from foobar import *y módulo foobar no define un __all__ lista, los nombres importados del módulo no Incluya aquellos con un guión bajo al principio. Digamos que es cuales son las que reflejan una convención, ya que este caso es un rincón bastante oscuro ;-).

La convención de subrayado inicial se usa ampliamente no solo para privada nombres, sino también por lo que C ++ llamaría protegido unos, por ejemplo, nombres de métodos que están totalmente destinados a ser reemplazados por subclases (incluso aquellos que tienen para ser anulado ya que en la clase base ellos raise NotImplementedError! -) son a menudo nombres de subrayado inicial único para indicar al código usar instancias de esa clase (o subclases) a las que dichos métodos no están destinados a ser llamados directamente.

Por ejemplo, para crear una cola segura para subprocesos con una disciplina de cola diferente a FIFO, se importa Cola, subclases Queue.Queue y anula métodos como _get y _put; "código de cliente" nunca llama a esos métodos ("gancho"), sino a los métodos públicos ("organizadores") como put y get (esto se conoce como el Método de plantilla patrón de diseño - ver p. ej. aquí para 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 charlas ahora están rotos. Puedes encontrar los dos primeros videos aquí y aquí.

respondido 24 nov., 19:00

Entonces, ¿cómo decides si usar _var_name vea la sección var_name + excluyéndolo de __all__? - endolito

@endolith Use un subrayado inicial para indicarle al lector de su código que probablemente no debería usarlo (por ejemplo, porque podría cambiarlo en la versión 2.0, o incluso 1.1); uso explícito __all__ siempre que quieras hacer el módulo from spam import * amigable (incluso en el intérprete interactivo). Entonces, la mayoría de las veces, la respuesta es ambas. - abarnert

@AlexMartelli ¿Esta regla relacionada con la importación se discute legalmente en algún lugar de documentos o en otro lugar? - vicrobot

Me gusta la analogía de C ++. En primer lugar, no me gusta cuando la gente llama al _ privada. Evidentemente estoy hablando de analogías, ya que nada es realmente privada en Python. Al sumergirnos en la semántica, diría que podemos atar el _ a Java protegido desde protegido en Java significa "clases derivadas y / o dentro del mismo paquete". Reemplazar paquete con módulo ya que PEP8 ya nos dice que _ no es solo una convención cuando se habla de * importaciones y ahí lo tienes. Y definitivamente __ sería equivalente a Java privada cuando se habla de identificadores dentro de una clase. - marius mucenicu

Si bien es una respuesta decente, también es muy autopromocional. - Desarrollador web híbrido

__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 con _classname__foo como 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.

Respondido 19 ago 09, 18:08

Acaba de cruzar __foo y curioso. ¿Cómo puede superponerse con nombres de métodos similares con otras clases? Quiero decir, todavía tienes que acceder a él como instance.__foo()(si el intérprete no le cambió el nombre), ¿verdad? - Bibhas Debnath

Este tipo recalca que from module import * no importa objetos con prefijo de subrayado. Por lo tanto, _foo es más que una simple convención. - dotancohen

@Bibhas: si clase B clase de subclases A, y ambos implementan foo(), entonces B.foo() anula el .foo() heredado de A. Una instancia de B solo podrá acceder B.foo(), excepto a través de super(B).foo(). - nada101

Para __dunder__ nombres, las invocaciones implícitas omiten el diccionario de instancias, por lo que tal vez sea un poco más que una convención de nomenclatura en algunos casos (consulte búsqueda de método especial sección en modelo de datos). - wim

._variable es semiprivado y solo para convenciones

.__variable a menudo se considera incorrectamente superprivado, mientras que su significado real es simplemente nombrar prevenir el acceso accidental[ XNMUX ]

.__variable__ normalmente se reserva para métodos o variables integrados

Todavía puedes acceder .__mangled variables si lo desea desesperadamente. Los guiones bajos dobles solo nombran, o renombran, la variable a algo como instance._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 a la alteración de nombres

>>> t._Test__a
'a'

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

contestado el 17 de mayo de 16 a las 11:05

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 doble subrayado con respecto a la herencia? - variable

Guión bajo único 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 que llama esta propiedad, _get_errors, es "privado", por lo que no debería acceder a él.

Dos guiones bajos al principio:

Esto causa mucha confusión. No debe usarse para crear un método privado. Debe usarse para evitar que su método sea anulado por una subclase o se 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 era de 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 desea que nadie pueda anularlo, y solo tiene la intención de acceder a él desde dentro de 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 al que Python debe llamar, no a ti. 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 función nativa que llama a estos métodos mágicos. A veces es solo un gancho de llamadas de Python en situaciones específicas. Por ejemplo __init__() se llama cuando el objeto se crea después __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 obtener más detalles, consulte la Guía PEP-8. Para obtener más métodos mágicos, consulte este PDF.

Respondido 21 ago 18, 20:08

Después de editar esta respuesta yo mismo, prefiero stackoverflow.com/a/8689983/1048186 - Josías Yoder

¿Qué quiere decir con "Como hemos visto, A.test () no llamó a los métodos B .__ test ()"? ¿Dónde ha llamado A.test ()? - variable

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

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

respondido 27 nov., 19:08

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

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

En este caso, lo que está sucediendo es que _ () es un alias para una función de localización que opera en texto para ponerlo en el idioma apropiado, etc. según la configuración regional. Por ejemplo, Sphinx hace esto y encontrará entre las importaciones

from sphinx.locale import l_, _

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

Respondido el 11 de enero de 12 a las 16:01

Dado que tanta gente se refiere a Raymond hablar, Lo haré un poco más fácil escribiendo lo que dijo:

La intención de los subrayados dobles no se trataba de 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 demás..

Digamos que no tiene una referencia local de perimeter in Circle. Ahora, una clase derivada Tire anula la implementación de perimeter, sin tocar area. Cuando usted llama Tire(5).area(), en teoría todavía debería estar usando Circle.perimeter para la computación, pero en realidad está usando Tire.perimeter, que no es el comportamiento previsto. Por eso necesitamos una referencia local en Circle.

Pero ¿por qué __perimeter en lugar de _perimeter? Porque _perimeter todaví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 subrayados dobles tienen alteración de nombres, por lo que hay muy pocas posibilidades de que la referencia local en la clase principal se anule en la clase derivada. por lo tanto "hace que sus subclases sean libres de anular cualquier método sin romper los demás".

Si su clase no se heredará, o si la anulación del método no rompe nada, entonces simplemente no necesita __double_leading_underscore.

Respondido el 16 de diciembre de 18 a las 11:12

Gracias, la diapositiva no se mostró correctamente, por lo que terminé sin aclarar por qué fallaba mi código. - cgte

Si uno realmente quiere hacer una variable de solo lectura, en mi humilde opinión, la mejor manera sería usar property () con solo pasarle un getter. 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 establecer variables privadas' marcadas como duplicadas con esta, pensé en agregar esta información adicional aquí.

Respondido 15 Abr '13, 02:04

Excelentes respuestas y todas son correctas. He proporcionado un ejemplo simple junto con una definición / significado simple.

Sentido:

alguna_variable --► es público, cualquiera puede ver esto.

_some_variable --► es público, cualquiera puede ver esto, pero es una convención para indicar privado ...advertencia 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 una variable privada.

Solo para ser honesto aquí Según 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)

Respondido el 21 de enero de 19 a las 22:01

_ _some_varaible - .... y reduce / oculta su visibilidad y se parece más a una variable privada. No, la cuestión es alterar los nombres, no oculta el método. - AMC

Los guiones bajos iniciales únicos 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.

Los guiones bajos iniciales y finales dobles se utilizan para métodos integrados, como __init__, __bool__, etc.

Los guiones bajos iniciales dobles sin contrapartes finales también son una convención, sin embargo, los métodos de clase serán destrozado por el intérprete. Para variables o nombres de funciones básicas no existe diferencia.

Respondido 19 ago 09, 18:08

Aquí hay un ejemplo ilustrativo simple sobre cómo las propiedades de doble subrayado 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 Python REPL, 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ó con la guardia baja en un entorno mucho más complejo.

Respondido 22 ago 14, 20:08

Tu pregunta es buena, no se trata solo de métodos. Las funciones y los objetos de los módulos suelen ir precedidos de un guión bajo y pueden ir precedidos de dos.

Pero los nombres __double_underscore no están alterados en los módulos, por ejemplo. 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 que se muestran en la ayuda (módulo).

Respondido 19 ago 09, 18:08

Además, los nombres que comienzan con uno o más guiones bajos que tienen dos o más guiones bajos finales se comportan de nuevo como cualquier otro nombre. - Bentley4

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, existe una convención que es seguida por la mayoría del código Python: un nombre prefijado 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 sujeto a cambios sin previo aviso.

referencia https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references

Respondido 07 Feb 15, 17:02

_ es mucho más similar, por ejemplo, a internal en c # que a private. El subrayado doble es mucho más similar a privado, entonces el subrayado es privado, diría yo. - Ini

Obtener los datos 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 yo 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 C ª#.

__

Debe usarse para evitar la colisión de nombres en la jerarquía de herencia y para evitar la unió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 utilizado _. Si desea indicar que algo no es para uso público, pero debe actuar como private utilizado __.

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

El problema es que el autor de una clase puede legítimamente pensar que "este atributo / nombre de método debe ser privado, solo accesible desde dentro de esta definición de clase" y usar la convención __private. Pero más adelante, un usuario de esa clase puede crear una subclase que legítimamente necesite acceso a ese nombre. Entonces, o la superclase tiene que ser modificada (lo cual puede ser difícil o imposible), o el código de la subclase tiene que usar nombres mutilados 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 le advierta cuando anula los métodos, encontrar el error puede llevarle un tiempo si ha anulado accidentalmente un método de una clase base.

respondido 04 nov., 17:17

  • _var: las variables con un guión bajo inicial en Python son variables clásicas, destinadas a informar a otros que usan su código que esta variable debe reservarse para uso interno. Se diferencian en un punto de las variables clásicas: no se importan al hacer una importación comodín de un objeto / módulo donde están definidas (excepciones al definir la __all__ variable). P.ej:

    # foo.py
    
    var = "var"
    _var = "_var"
    
    # bar.py
    
    from foo import *
    
    print(dir())  # list of defined objects, contains 'var' but not '_var'
    print(var)    # var
    print(_var)   # NameError: name '_var' is not defined
    
  • _ : el guión bajo simple es un caso especial de las variables de guión bajo único iniciales. Se utiliza por convención como una variable de papelera, para almacenar un valor al que no se pretende acceder posteriormente. Tampoco se importa mediante importaciones comodín. Por ejemplo: esto for El bucle imprime "No debo hablar en clase" 10 veces y nunca necesita acceder al _ variable.

    for _ in range(10):
        print("I must not talk in class")
    
  • __var: variables de subrayado inicial doble (al menos dos subrayados iniciales, como máximo un subrayado final). Cuando se usan como atributos de clase (variables y métodos), estas variables están sujetas a cambios de nombre: fuera de la clase, Python cambiará el nombre del atributo a _<Class_name>__<attribute_name>. Ejemplo:

    class MyClass:
        __an_attribute = "attribute_value"
    
    my_class = MyClass()
    print(my_class._MyClass__an_attribute)  # "attribute_value"
    print(my_class.__an_attribute)  # AttributeError: 'MyClass' object has no attribute '__an_attribute'
    

    Cuando se utilizan como variables fuera de una clase, se comportan como variables de subrayado iniciales únicas.

  • __var__: variables de subrayado inicial y final doble (al menos dos subrayados iniciales y finales). También llamado dunders. Python utiliza esta convención de nomenclatura para definir variables internamente. Evite el uso de esta convención para evitar conflictos de nombres que podrían surgir con las actualizaciones de Python. Las variables Dunder se comportan como variables de subrayado principal único: no están sujetas a alteración de nombres cuando se usan dentro de clases, pero no se importan en importaciones con comodines.

Respondido el 06 de enero de 21 a las 14:01

En el caso de los métodos, puede usar el doble subrayado para ocultar los 'métodos' privados con el siguiente patrón:

# Private methods of MyClass
def _MyClass__do_something(obj:'MyClass'):
    print('_MyClass__do_something() called. type(obj) = {}'.format(type(obj)))

class MyClass():
    def __init__(self):
        __do_something(self)

mc = MyClass()

Salida:

_MyClass__do_something() called. type(obj) = <class '__main__.MyClass'>

Me encontré con esto hoy cuando intenté usar doble subrayado para los métodos de clase y obtuve el NameError: name '_<class><method>' is not defined error.

Respondido el 22 de diciembre de 20 a las 20:12

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.