¿Cuál es el significado del guión bajo simple y doble antes del nombre de un objeto?

Resuelto ivanleoncz asked hace 15 años • 18 respuestas

¿Qué representan los guiones bajos iniciales simples y dobles antes del nombre de un objeto en Python?

ivanleoncz avatar Aug 20 '09 00:08 ivanleoncz
Aceptado

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 ejemplo from 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, donde classnameestá 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!'}
Andrew Keeton avatar Aug 19 '2009 17:08 Andrew Keeton
  • _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__foocomo 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.

Ned Batchelder avatar Aug 19 '2009 17:08 Ned Batchelder

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

Alex Martelli avatar Aug 19 '2009 17:08 Alex Martelli

._variableEs semiprivado y está destinado sólo para convenciones.

.__variablea 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 .__mangledlas 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__variableen lugar de solo al nombre de doble guión bajo, puede acceder al valor oculto

NickCSE avatar Sep 27 '2012 20:09 NickCSE