Alguém pode explicar o significado exato de ter sublinhados à esquerda antes do nome de um objeto em Python e a diferença entre ambos?
Além disso, esse significado permanece o mesmo, independentemente de o objeto em questão ser uma variável, uma função, um método etc.?
python
oop
naming-conventions
ivanleoncz
fonte
fonte
Respostas:
Sublinhado único
Os nomes, em uma classe, com um sublinhado à esquerda são simplesmente para indicar a outros programadores que o atributo ou método se destina a ser privado. No entanto, nada de especial é feito com o próprio nome.
Para citar PEP-8 :
Sublinhado duplo (Mangling de nome)
Nos documentos do Python :
E um aviso da mesma página:
Exemplo
fonte
__
sublinhado duplo como um nome de variável? comoa, __ = foo()
Excelentes respostas até agora, mas faltam alguns petiscos. Um único sublinhado principal não é exatamente apenas uma convenção: se você usar
from foobar import *
, e o módulofoobar
não definir uma__all__
lista, os nomes importados do módulo não incluirão aqueles com um sublinhado principal. Digamos que é principalmente uma convenção, já que este caso é um canto bastante obscuro ;-).A convenção de sublinhado principal é amplamente usada não apenas para nomes particulares , mas também para o que o C ++ chamaria de protegidos - por exemplo, nomes de métodos que se destinam totalmente a serem substituídos por subclasses (mesmo aqueles que precisam ser substituídos desde a classe base eles
raise NotImplementedError
! -) geralmente são nomes com sublinhado à esquerda para indicar ao código usando instâncias dessa classe (ou subclasses) que esses métodos não devem ser chamados diretamente.Por exemplo, para criar uma fila de thread-safe com uma disciplina de enfileiramento diferente da FIFO, importa-se Fila, subclasses Queue.Queue e substitui métodos como
_get
e_put
; O "código do cliente" nunca chama esses métodos ("ganchos"), mas os métodos públicos ("organizando") comoput
eget
(isso é conhecido como padrão de design do Método do Modelo - veja, por exemplo, aqui uma apresentação interessante baseada em um vídeo) de uma palestra minha sobre o assunto, com a adição de sinopses da transcrição).Edit: Os links de vídeo na descrição das conversas agora estão quebrados. Você pode encontrar os dois primeiros vídeos aqui e aqui .
fonte
_var_name
ou usarvar_name
+ excluindo-o__all__
?__all__
sempre que desejar tornar o módulofrom spam import *
amigável (inclusive no intérprete interativo). Então, na maioria das vezes, a resposta é ambas ._
privado . Evidentemente, estou falando de analogias, já que nada é verdadeiramente privado em Python. Ao mergulhar na semântica, eu diria que podemos vincular o protegido_
ao Java, já que o proctected em Java significa "classes derivadas e / ou dentro do mesmo pacote". Substitua pacote pelo módulo, já que o PEP8 já nos diz que não é apenas uma convenção quando se fala de importações, e aí está. E definitivamente seria equivalente ao privado de Java ao falar sobre identificadores dentro de uma classe._
*
__
__foo__
: esta é apenas uma convenção, uma maneira de o sistema Python usar nomes que não entrem em conflito com os nomes de usuário._foo
: esta é apenas uma convenção, uma maneira do programador indicar que a variável é privada (o que quer que isso signifique em Python).__foo
: isso tem um significado real: o intérprete substitui esse nome_classname__foo
por uma maneira de garantir que o nome não se sobreponha a um nome semelhante em outra classe.Nenhuma outra forma de sublinhado tem significado no mundo Python.
Não há diferença entre classe, variável, global, etc. nessas convenções.
fonte
__foo
e curioso. Como ele pode se sobrepor a nomes de métodos semelhantes a outras classes? Quero dizer, você ainda precisa acessá-lo comoinstance.__foo()
(se não fosse renomeado pelo intérprete), certo?from module import *
não importa objetos com prefixo sublinhado. Portanto,_foo
é mais do que apenas uma convenção.B
subclasses classA
, e ambos implementamfoo()
, entãoB.foo()
substitui o.foo()
herdado deA
. Uma instância deB
somente poderá acessarB.foo()
, exceto viasuper(B).foo()
.__dunder__
nomes, invocações implícitas ignoram o dicionário da instância, portanto, talvez seja um pouco mais do que apenas uma convenção de nomenclatura em alguns casos (consulte a seção de pesquisa de métodos especiais no modelo de dados).._variable
é semi-privado e destinado apenas a convenções.__variable
geralmente é considerado incorretamente superprivado, enquanto o significado real é apenas alterar o nome para impedir o acesso acidental [1].__variable__
é normalmente reservado para métodos ou variáveis incorporadasVocê ainda pode acessar
.__mangled
variáveis se desejar desesperadamente. O sublinhado duplo apenas nomemangeia ou renomeia a variável para algo comoinstance._className__mangled
Exemplo:
t._b é acessível porque está oculto apenas por convenção
t .__ a não foi encontrado porque não existe mais devido à manipulação de nomes
Ao acessar, em
instance._className__variable
vez de apenas o nome de sublinhado duplo, você pode acessar o valor ocultofonte
Sublinhado único no início:
Python não possui métodos particulares reais. Em vez disso, um sublinhado no início de um método ou nome de atributo significa que você não deve acessar esse método, porque ele não faz parte da API.
(Este trecho de código foi retirado do código-fonte do django: django / forms / forms.py). Nesse código,
errors
é uma propriedade pública, mas o método que essa propriedade chama, _get_errors, é "privado", portanto você não deve acessá-lo.Dois sublinhados no início:
Isso causa muita confusão. Não deve ser usado para criar um método privado. Deve ser usado para evitar que seu método seja substituído por uma subclasse ou acessado acidentalmente. Vamos ver um exemplo:
Resultado:
Agora crie uma subclasse B e faça customização para o método __test
A saída será ....
Como vimos, A.test () não chamou os métodos B .__ test (), como poderíamos esperar. Mas, de fato, esse é o comportamento correto para __. Os dois métodos chamados __test () são renomeados automaticamente (desconfigurados) para _A__test () e _B__test (), para que não sejam substituídos acidentalmente. Quando você cria um método começando com __, significa que você não deseja que ninguém possa substituí-lo e só pretende acessá-lo de dentro de sua própria classe.
Dois sublinhados no início e no final:
Quando vemos um método como
__this__
, não o chame. Este é um método que o python deve chamar, não você. Vamos dar uma olhada:Sempre existe um operador ou função nativa que chama esses métodos mágicos. Às vezes, é apenas um python gancho chama em situações específicas. Por exemplo,
__init__()
é chamado quando o objeto é criado após__new__()
ser chamado para criar a instância ...Vamos dar um exemplo ...
Para mais detalhes, consulte o guia PEP-8 . Para mais métodos mágicos, consulte este PDF .
fonte
Às vezes, você tem o que parece ser uma tupla com um sublinhado à esquerda, como em
Nesse caso, o que está acontecendo é que _ () é um alias para uma função de localização que opera em texto para colocá-lo no idioma apropriado etc. com base no código do idioma. Por exemplo, o Sphinx faz isso, e você encontrará entre as importações
e em sphinx.locale, _ () é designado como um alias de alguma função de localização.
fonte
Como tantas pessoas estão se referindo à palestra de Raymond , eu vou facilitar um pouco, escrevendo o que ele disse:
Digamos que você não mantenha uma referência local de
perimeter
inCircle
. Agora, uma classe derivadaTire
substitui a implementação deperimeter
, sem tocararea
. Quando você ligaTire(5).area()
, em teoria, ele ainda deve estar sendo usadoCircle.perimeter
para computação, mas, na realidade, está sendo usadoTire.perimeter
, o que não é o comportamento pretendido. É por isso que precisamos de uma referência local no Circle.Mas por que ao
__perimeter
invés de_perimeter
? Porque_perimeter
ainda dá à classe derivada a chance de substituir:Os sublinhados duplos têm nomes diferentes, portanto, há muito pouca chance de a referência local na classe pai ser substituída na classe derivada. assim " torna suas subclasses livres para substituir qualquer método sem quebrar os outros ".
Se sua classe não será herdada ou a substituição de método não quebra nada, você simplesmente não precisa
__double_leading_underscore
.fonte
Se alguém realmente deseja criar uma variável somente leitura, o IMHO é a melhor maneira de usar a propriedade () com apenas o getter passado para ela. Com property (), podemos ter controle total sobre os dados.
Entendo que o OP fez uma pergunta um pouco diferente, mas como encontrei outra pergunta pedindo 'como definir variáveis privadas' marcada como duplicada com essa, pensei em adicionar essas informações adicionais aqui.
fonte
Codificação para https://dbader.org/blog/meaning-of-underscores-in-python
fonte
As respostas são ótimas e todas estão corretas. Forneci um exemplo simples, juntamente com uma definição / significado simples.
Significado:
some_variable --► é público, qualquer pessoa pode ver isso.
_some_variable --► é público, qualquer pessoa pode ver isso, mas é uma convenção indicar privado ... aviso que nenhuma aplicação é executada pelo Python.
__some_varaible --► Python substitui o nome da variável por _classname__some_varaible (nome do arquivo AKA) e reduz / oculta sua visibilidade e se parece mais com uma variável privada.
Apenas para ser honesto aqui De acordo com a documentação do Python
O exemplo:
fonte
Os sublinhados principais líderes são uma convenção. não há diferença do ponto de vista do intérprete se os nomes começam com um único sublinhado ou não.
Duplos ataque e de fuga sublinhados são utilizados para embutido métodos, tais como
__init__
,__bool__
, etc.Os sublinhados iniciais duplos sem contrapartes à direita também são uma convenção; no entanto, os métodos de classe serão confundidos pelo intérprete. Para variáveis ou nomes de funções básicas, não existe diferença.
fonte
Sua pergunta é boa, não se trata apenas de métodos. Funções e objetos em módulos são geralmente prefixados com um sublinhado e também podem ser prefixados por dois.
Mas os nomes __double_underscore não são modificados por nome nos módulos, por exemplo. O que acontece é que os nomes que começam com um (ou mais) sublinhados não são importados se você importar tudo de um módulo (da importação de módulo *), nem os nomes mostrados na ajuda (módulo).
fonte
Aqui está um exemplo ilustrativo simples de como as propriedades de sublinhado duplo podem afetar uma classe herdada. Portanto, com a seguinte configuração:
se você criar uma instância filho no python REPL, verá o abaixo
Isso pode ser óbvio para alguns, mas me pegou de surpresa em um ambiente muito mais complexo
fonte
Variáveis de instância "privadas" que não podem ser acessadas, exceto de dentro de um objeto, não existem no Python. No entanto, existe uma convenção seguida pela maioria dos códigos Python: um nome prefixado com um sublinhado (por exemplo, _spam) deve ser tratado como uma parte não pública da API (seja uma função, um método ou um membro de dados) . Deve ser considerado um detalhe da implementação e sujeito a alterações sem aviso prévio.
referência https://docs.python.org/2/tutorial/classes.html#private-variables-and-class-local-references
fonte
Obter os fatos de _ e __ é bastante fácil; as outras respostas as expressam muito bem. O uso é muito mais difícil de determinar.
É assim que eu vejo:
Deve ser usado para indicar que uma função não é para uso público, como por exemplo uma API. Isso e a restrição de importação fazem com que ele se comporte de maneira semelhante
internal
em c #.Deve ser usado para evitar colisão de nomes na hierarquia de herança e para evitar a ligação tardia. Bem como privado em c #.
==>
Se você deseja indicar que algo não é para uso público, mas deve agir como um
protected
uso_
. Se você deseja indicar que algo não é para uso público, mas deve agir como umprivate
uso__
.Esta é também uma citação de que gosto muito:
Mas o problema é que, na minha opinião, se não houver um IDE que avise quando você substituir métodos, encontrar o erro poderá demorar um pouco se você substituir acidentalmente um método de uma classe base.
fonte