¿Cuál es el significado del guión bajo simple y doble antes del nombre de un objeto?
¿Qué representan los guiones bajos iniciales simples y dobles antes del nombre de un objeto en Python?
Subrayado simple
En una clase, los nombres con un guión bajo inicial indican a otros programadores que el atributo o método está destinado a usarse dentro de esa clase. Sin embargo, la privacidad no se aplica de ninguna manera. El uso de guiones bajos iniciales para funciones en un módulo indica que no se debe importar desde ningún otro lugar.
De la guía de estilo PEP-8 :
_single_leading_underscore
: indicador débil de "uso interno". Por ejemplofrom M import *
, no importa objetos cuyo nombre comience con un guión bajo.
Doble guión bajo (cambio de nombres)
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 con_classname__spam
, dondeclassname
está el nombre de la clase actual sin los guiones bajos iniciales. Esta manipulación se realiza sin tener en cuenta la posición sintáctica del identificador, por lo que se puede utilizar para definir variables de clase y instancia privada de clase, métodos, variables almacenadas en globales e incluso variables almacenadas en instancias. privado para esta clase en instancias de otras clases.
Y una advertencia de la misma página:
La manipulación de nombres tiene como objetivo brindar 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 mediante 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!'}
_foo
: Sólo 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_classname__foo
como una forma de garantizar que el nombre no se superponga con un nombre similar en otra clase.__foo__
: Sólo una convención. Una forma para que el sistema Python use nombres que no entren en conflicto con los nombres de usuario.
Ninguna otra forma de guión bajo tiene significado en el mundo de Python. Además, no hay diferencia entre clase, variable, global, etc. en estas convenciones.
Excelentes respuestas hasta ahora, pero faltan algunas cositas. Un guión bajo inicial no es exactamente solo una convención: si usa from foobar import *
y el módulo foobar
no define una __all__
lista, los nombres importados desde el módulo no incluyen aquellos con un guión bajo inicial. Digamos que es más que nada una convención, ya que este caso es un rincón bastante oscuro ;-).
La convención de guión bajo inicial se usa ampliamente no sólo para nombres privados , sino también para los que C++ llamaría protegidos , por ejemplo, nombres de métodos que están totalmente pensados para ser anulados por subclases (incluso aquellos que deben ser anulados ya que en la clase base ellos raise NotImplementedError
!-) son a menudo nombres de guión bajo inicial único para indicar al código que utiliza instancias de esa clase (o subclases) que dichos métodos no deben llamarse directamente.
Por ejemplo, para crear una cola segura para subprocesos con una disciplina de cola diferente a FIFO, se importa Queue, subclases Queue.Queue y anula métodos como _get
y _put
; El "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 patrón de diseño del método de plantilla ; consulte, por ejemplo, aquí una presentación interesante basada en un vídeo). de una charla mía sobre el tema, con la adición de sinopsis de la transcripción).
Editar: Los enlaces de vídeo en la descripción de las charlas ahora están rotos. Puedes encontrar los dos primeros vídeos aquí y aquí .
._variable
Es semiprivado y está destinado sólo para convenciones.
.__variable
a menudo se considera incorrectamente superprivado, mientras que su significado real es simplemente cambiar nombres para evitar el acceso accidental [1]
.__variable__
normalmente está reservado para métodos o variables integrados
Aún puedes acceder a .__mangled
las variables si lo deseas desesperadamente. Los guiones bajos dobles simplemente cambian el nombre o cambian el nombre de 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 a una alteración de nombres
>>> t._Test__a
'a'
Al acceder instance._className__variable
en lugar de solo al nombre de doble guión bajo, puede acceder al valor oculto