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


Quiero aclarar esto de una vez por todas. ¿Puede alguien explicar el significado exacto de tener guiones bajos antes del nombre de un objeto en Python? También explique la diferencia entre un subrayado principal simple y doble. Además, ¿ese significado permanece igual si el objeto en cuestión es una variable, una función, un método, etc.?


981
2017-08-19 17:15


origen


Respuestas:


Single Underscore

Los nombres, en una clase, con un subrayado inicial son simplemente para indicar a otros programadores que el atributo o método debe ser privado. Sin embargo, no se hace nada especial con el nombre en sí.

Citar PEP-8:

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

Doble subrayado (nombre de manipulación)

De los documentos de Python:

Cualquier identificador de la forma __spam (al menos dos guiones bajos principales, como máximo un guión bajo final) se reemplaza textualmente por _classname__spam, dónde classname es el nombre de la clase actual con subrayado (s) principal (es) despojado (s). Este cambio se realiza sin tener en cuenta la posición sintáctica del identificador, por lo que se puede usar para definir variables de clase y instancia de clase privada, 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 el borrado con 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; aún es posible para un alma determinada acceder o modificar 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!'}

920
2017-08-19 17:52



Excelentes respuestas hasta ahora, pero faltan algunas cositas. Un único guion bajo inicial no es exactamente sólo una convención: si usa from foobar import *y módulo foobar no define un __all__ lista, los nombres importados del módulo no haga incluye aquellos con un guion bajo. Digamos que es principalmente una convención, ya que este caso es un rincón bastante oscuro ;-).

La convención de guión bajo se usa ampliamente no solo para privado nombres, sino también para lo que llamaría C ++ protegido unos, por ejemplo, nombres de métodos que están completamente destinados a ser reemplazados por subclases (incluso aquellos que tener ser anulado ya que en la clase base raise NotImplementedError! -) a menudo son nombres de guion bajo individuales para indicar el código utilizando instancias de esa clase (o subclases) 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 colas diferente que FIFO, una importa Cola, subclases Queue.Queue y anula tales métodos como _gety _put; El "código de cliente" nunca llama a esos ("gancho") métodos, sino más bien a los ("organizar") métodos públicos tales como puty get (esto se conoce como el Método de plantilla patrón de diseño: consulte 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).


268
2017-08-19 17:21



__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 (sea 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 un significado en el mundo de Python.

No hay diferencia entre clase, variable, global, etc. en estas convenciones.


245
2017-08-19 17:17



._variable es semiprivado y significa solo para la convención

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

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

Aún puedes acceder .__mangled variables si lo deseas desesperadamente. El doble subraya solo nombra o cambia el nombre de la variable a algo así 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 manipulación de nombres

>>> t._Test__a
'a'

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


175



Un guión bajo al comienzo:

Python no tiene métodos privados reales, por lo que un guión bajo al comienzo de un método o nombre de atributo significa que no deberías 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)

fragmento de código tomado del código fuente de django (django / forms / forms.py). Esto significa que los errores son una propiedad, y es parte del módulo, pero el método que esta propiedad llama, _get_errors, es "privado", por lo que no debe acceder a él.

Dos guiones bajos al comienzo:

Esto causa mucha confusión. No debe usarse para crear un método privado. Se debe usar 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 test method in class A"

    def test(self):
        self.__test()

a = A()
a.test()

Salida:

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

Ahora crea una subclase B y personaliza 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 __. Por lo tanto, cuando crea un método que comienza con __ significa que no desea que nadie pueda anularlo, solo podrá accederse desde dentro de la propia clase.

Dos guiones bajos al principio y al final:

Cuando vemos un método como __this__no lo llames Porque significa que es un método que llama python, 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 función nativa que llama a estos métodos mágicos. A veces es solo un gancho llamado 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 más detalles Guía PEP-8 ayudará más.

Encuentra más métodos mágicos en Python aquí. https://github.com/RafeKettler/magicmethods/blob/master/magicmethods.pdf


86



A veces tienes lo que parece ser una tupla con un guion 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á entre las importaciones

from sphinx.locale import l_, _

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


15



Subrayar (_) en Python

Los siguientes son diferentes lugares donde _ se usa en Python:

Solo subrayado:

  • En intérprete
  • Después de un nombre
  • Antes de un nombre

Doble subrayado:

  • __leading_double_underscore

  • antes después

  • Single Underscore

En Intérprete:

_ devuelve el valor del último valor de expresión ejecutada en Python REPL

>>> a = 10
>>> b = 10
>>> _
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name '_' is not defined
>>> a+b
20
>>> _
20
>>> _ * 2
40
>>> _
40
>>> _ / 2
20

Por ignorar valores:

Múltiples veces no queremos valores de retorno en ese momento asignar esos valores a wnderscore. Usó como variable desechable.

# Ignore a value of specific location/index
for _ in rang(10)
    print "Test"

# Ignore a value when unpacking
a,b,_,_ = my_method(var1)

Después de un nombre

Python tiene sus palabras clave predeterminadas que no podemos usar como nombre de la variable. Para evitar tal conflicto entre la palabra clave y la variable de python usamos guiones bajos después del nombre

Ejemplo:

>>> class MyClass():
...     def __init__(self):
...             print "OWK"

>>> def my_defination(var1 = 1, class_ = MyClass):
...     print var1
...     print class_

>>> my_defination()
1
__main__.MyClass
>>>

Antes de un nombre

El guión bajo antes de la variable / función / nombre del método indica al programador que es solo para uso interno, que puede modificarse siempre que lo desee la clase.

Aquí el prefijo de nombre por guión bajo se trata como no público. Si especifica desde Importar *, todo el nombre comienza con _ no se importará.

Python no especifica realmente privado, por lo que se pueden llamar directamente desde otros módulos si se especifica en todas, También lo llamamos débil Privado

class Prefix:
...     def __init__(self):
...             self.public = 10
...             self._private = 12
>>> test = Prefix()
>>> test.public
10
>>> test._private
12
Python class_file.py

def public_api():
    print "public api"

def _private_api():
    print "private api"

Archivo de llamada de REPL

>>> from class_file import *
>>> public_api()
public api

>>> _private_api()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name '_private_api' is not defined

>>> import class_file
>>> class_file.public_api()
public api
>>> class_file._private_api()
private api
Double Underscore(__)

__leading_double_underscore

El subrayado doble inicial le indica al intérprete de Python que reescriba el nombre para evitar el conflicto en la subclase. Interpreter cambia el nombre de la variable con la extensión de clase y esa característica conocida como Mangling. testFile.py

class Myclass():
    def __init__(self):
        self.__variable = 10

Llamando desde REPL

>>> import testFile
>>> obj = testFile.Myclass()
>>> obj.__variable
Traceback (most recent call last):
File "", line 1, in
AttributeError: Myclass instance has no attribute '__variable'
nce has no attribute 'Myclass'
>>> obj._Myclass__variable
10

En Mangling, el intérprete python modifica el nombre de la variable con ___. Por lo tanto, usa varias veces como miembro privado porque otra clase no puede acceder a esa variable directamente. El propósito principal de __ es usar variable / método solo en clase. Si quieres usarlo fuera de la clase, puedes hacer una API pública.

class Myclass():
    def __init__(self):
        self.__variable = 10
    def func(self)
        print self.__variable

Llamando desde REPL

>>> import testFile
>>> obj = testFile.Myclass()
>>> obj.func()
10

__ANTES DESPUÉS__

El nombre con inicio con __ y termina con el mismo considera métodos especiales en Python. Python proporciona estos métodos para usarlo como sobrecarga del operador según el usuario.

Python proporciona esta convención para diferenciar entre la función definida por el usuario y la función del módulo

class Myclass():
    def __add__(self,a,b):
        print a*b

Llamando desde REPL

>>> import testFile
>>> obj = testFile.Myclass()
>>> obj.__add__(1,2)
2
>>> obj.__add__(5,2)
10

Referencia


10



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 él. Con property () podemos tener un control total 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 desde que encontré otra pregunta que preguntaba 'cómo establecer las variables privadas' marcadas como duplicadas con esta, pensé en agregar esta información adicional aquí.


7



Los guiones bajos únicos son una convención. no hay diferencia desde el punto de vista del intérprete si los nombres comienzan con un solo guión bajo o no.

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

Los caracteres de subrayado 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.


4