Por que algumas funções têm sublinhados “__” antes e depois do nome da função?


424

Esse "sublinhado" parece ocorrer muito, e eu queria saber se isso era um requisito na linguagem Python, ou apenas uma questão de convenção?

Além disso, alguém poderia nomear e explicar quais funções tendem a ter sublinhados e por que ( __init__por exemplo)?


8
@ AustinHenley: Não para sublinhados duplos antes e depois do nome. Você está pensando em sublinhados apenas antes do nome.



@MackM Observe que esta pergunta pergunta sobre os sublinhados antes e depois do nome, e o destino duplicado que você propôs pergunta sobre os sublinhados apenas antes do nome. No entanto, admito que algumas das respostas também abrangem este caso.
Georgy

Respostas:


526

No Python PEP 8 - Guia de Estilo para Código Python :

Descritivo: Estilos de Nomenclatura

Os seguintes formulários especiais usando sublinhados à esquerda ou à direita são reconhecidos (geralmente podem ser combinados com qualquer convenção de caso):

  • _single_leading_underscore: indicador fraco de "uso interno". Por exemplo from M import *, não importa objetos cujo nome comece com um sublinhado.

  • single_trailing_underscore_: usado por convenção para evitar conflitos com a palavra-chave Python, por exemplo

    Tkinter.Toplevel(master, class_='ClassName')

  • __double_leading_underscore: ao nomear um atributo de classe, invoca o nome errado (dentro da classe FooBar, __bootorna-se _FooBar__boo; veja abaixo).

  • __double_leading_and_trailing_underscore__: objetos ou atributos "mágicos" que vivem em espaços para nome controlados pelo usuário. Por exemplo __init__, __import__ou __file__. Nunca invente esses nomes; use-os apenas como documentado.

Observe que nomes com sublinhados duplos à esquerda e à direita são essencialmente reservados para o próprio Python: "Nunca invente esses nomes; use-os apenas como documentado".


6
Raymond também explica por que você iria querer o nome desconfiguração comportamento a partir de cerca de 34 minutos neste vídeo: youtube.com/watch?v=HTLu2DFOdTg
johncip

5
Portanto, a escolha entre o sublinhado inicial simples e o sublinhado inicial duplo em um nome é como escolher entre protegido e privado em C ++ e Java? _single_leading_underscore pode ser alterado por filhos, mas __double_leading_underscore não pode?
Alex W

2
__double_leading_underscoreainda é público , a variável é renomeada para evitar conflitos.
cz 21/09

59

Os outros entrevistados estão corretos ao descrever os sublinhados duplos à esquerda e à direita como uma convenção de nomenclatura para métodos "especiais" ou "mágicos".

Embora você possa chamar esses métodos diretamente ( [10, 20].__len__()por exemplo), a presença dos sublinhados é uma dica de que esses métodos devem ser chamados indiretamente ( len([10, 20])por exemplo). A maioria dos operadores python tem um método "mágico" associado (por exemplo, a[x]é a maneira usual de invocar a.__getitem__(x)).



5

Na verdade, eu uso nomes de métodos _ quando preciso diferir entre nomes de classes pai e filho. Eu li alguns códigos que usavam essa maneira de criar classes pai-filho. Como exemplo, eu posso fornecer este código:

class ThreadableMixin:
   def start_worker(self):
       threading.Thread(target=self.worker).start()

   def worker(self):
      try:
        self._worker()
    except tornado.web.HTTPError, e:
        self.set_status(e.status_code)
    except:
        logging.error("_worker problem", exc_info=True)
        self.set_status(500)
    tornado.ioloop.IOLoop.instance().add_callback(self.async_callback(self.results))

...

e a criança que tem um método _worker

class Handler(tornado.web.RequestHandler, ThreadableMixin):
   def _worker(self):
      self.res = self.render_string("template.html",
        title = _("Title"),
        data = self.application.db.query("select ... where object_id=%s", self.object_id)
    )

...


Não é para isso que serve o prefixo duplo sublinhado?
AMC

1

Esta convenção é usada para variáveis ​​ou métodos especiais (o chamado "método mágico") como __init__e __len__. Esses métodos fornecem recursos sintáticos especiais ou fazem coisas especiais.

Por exemplo, __file__indica a localização do arquivo Python, __eq__é executado quando a a == bexpressão é executada.

É claro que um usuário pode criar um método especial personalizado, o que é um caso muito raro, mas geralmente pode modificar alguns dos métodos especiais internos (por exemplo, você deve inicializar a classe com a __init__qual será executada primeiro quando uma instância de uma classe é criado).

class A:
    def __init__(self, a):  # use special method '__init__' for initializing
        self.a = a
    def __custom__(self):  # custom special method. you might almost do not use it
        pass

0

Adicionado um exemplo para entender o uso de __ em python. Aqui está a lista de Todos __

https://docs.python.org/3/genindex-all.html#_

Certas classes de identificadores (além de palavras-chave) têm significados especiais. Qualquer uso de * nomes, em qualquer outro contexto, que não siga o uso explicitamente documentado, está sujeito a quebra sem aviso prévio.

Restrição de acesso usando __

"""
Identifiers:
-  Contain only (A-z, 0-9, and _ )
-  Start with a lowercase letter or _.
-  Single leading _ :  private
-  Double leading __ :  strong private
-  Start & End  __ : Language defined Special Name of Object/ Method
-  Class names start with an uppercase letter.
-

"""


class BankAccount(object):
    def __init__(self, name, money, password):
        self.name = name            # Public
        self._money = money         # Private : Package Level
        self.__password = password  # Super Private

    def earn_money(self, amount):
        self._money += amount
        print("Salary Received: ", amount, " Updated Balance is: ", self._money)

    def withdraw_money(self, amount):
        self._money -= amount
        print("Money Withdraw: ", amount, " Updated Balance is: ", self._money)

    def show_balance(self):
        print(" Current Balance is: ", self._money)


account = BankAccount("Hitesh", 1000, "PWD")  # Object Initalization

# Method Call
account.earn_money(100)

# Show Balance
print(account.show_balance())

print("PUBLIC ACCESS:", account.name)  # Public Access

# account._money is accessible because it is only hidden by convention
print("PROTECTED ACCESS:", account._money)  # Protected Access

# account.__password will throw error but account._BankAccount__password will not
# because __password is super private
print("PRIVATE ACCESS:", account._BankAccount__password)

# Method Call
account.withdraw_money(200)

# Show Balance
print(account.show_balance())

# account._money is accessible because it is only hidden by convention
print(account._money)  # Protected Access
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.