Na dúvida, deixe "público" - quero dizer, não adicione nada para obscurecer o nome do seu atributo. Se você tem uma aula com algum valor interno, não se preocupe com isso. Em vez de escrever:
class Stack(object):
def __init__(self):
self.__storage = [] # Too uptight
def push(self, value):
self.__storage.append(value)
escreva isso por padrão:
class Stack(object):
def __init__(self):
self.storage = [] # No mangling
def push(self, value):
self.storage.append(value)
Esta é certamente uma forma controversa de fazer as coisas. Os novatos em Python simplesmente odeiam e até mesmo alguns caras mais velhos do Python desprezam esse padrão - mas é o padrão de qualquer maneira, então eu realmente recomendo que você o siga, mesmo se você se sentir desconfortável.
Se você realmente deseja enviar a mensagem "Não posso tocar nisso!" para seus usuários, a maneira usual é preceder a variável com um sublinhado. Isso é apenas uma convenção, mas as pessoas entendem e tomam cuidado redobrado ao lidar com essas coisas:
class Stack(object):
def __init__(self):
self._storage = [] # This is ok but pythonistas use it to be relaxed about it
def push(self, value):
self._storage.append(value)
Isso também pode ser útil para evitar conflito entre nomes de propriedades e nomes de atributos:
class Person(object):
def __init__(self, name, age):
self.name = name
self._age = age if age >= 0 else 0
@property
def age(self):
return self._age
@age.setter
def age(self, age):
if age >= 0:
self._age = age
else:
self._age = 0
E o sublinhado duplo? Bem, a magia de sublinhado duplo é usada principalmente para evitar sobrecarga acidental de métodos e conflitos de nome com atributos das superclasses . Pode ser muito útil se você escrever uma classe que deve ser estendida muitas vezes.
Se quiser usá-lo para outros fins, você pode, mas não é comum nem recomendado.
EDIT : Por que isso acontece? Bem, o estilo Python usual não enfatiza tornar as coisas privadas - pelo contrário! Existem muitas razões para isso - a maioria delas controversas ... Vamos ver algumas delas.
Python tem propriedades
A maioria das linguagens OO hoje usa a abordagem oposta: o que não deve ser usado não deve ser visível, portanto, os atributos devem ser privados. Teoricamente, isso resultaria em classes mais gerenciáveis e menos acopladas, porque ninguém mudaria os valores dentro dos objetos de maneira imprudente.
No entanto, não é tão simples. Por exemplo, as classes Java têm muitos atributos e getters que apenas obtêm os valores e setters que apenas definem os valores. Você precisa, digamos, de sete linhas de código para declarar um único atributo - o que um programador Python diria que é desnecessariamente complexo. Além disso, na prática, você apenas escreve todo esse código para obter um campo público, já que pode alterar seu valor usando getters e setters.
Então, por que seguir essa política privada por padrão? Basta tornar seus atributos públicos por padrão. Claro, isso é problemático em Java, porque se você decidir adicionar alguma validação ao seu atributo, seria necessário alterar todos
person.age = age;
em seu código para, digamos,
person.setAge(age);
setAge()
ser:
public void setAge(int age) {
if (age >= 0) {
this.age = age;
} else {
this.age = 0;
}
}
Então, em Java (e outras linguagens), o padrão é usar getters e setters de qualquer maneira, porque eles podem ser chatos de escrever, mas podem poupar muito tempo se você se encontrar na situação que descrevi.
No entanto, você não precisa fazer isso em Python, já que Python tem propriedades. Se você tem esta classe:
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
e então você decide validar idades, você não precisa alterar as person.age = age
partes do seu código. Basta adicionar uma propriedade (conforme mostrado abaixo)
class Person(object):
def __init__(self, name, age):
self.name = name
self._age = age if age >= 0 else 0
@property
def age(self):
return self._age
@age.setter
def age(self, age):
if age >= 0:
self._age = age
else:
self._age = 0
Se você pode fazer isso e ainda usar person.age = age
, por que adicionaria campos privados e getters e setters?
(Além disso, consulte Python não é Java e este artigo sobre os malefícios do uso de getters e setters .).
Tudo é visível de qualquer maneira - e tentar esconder apenas complica o seu trabalho
Mesmo em linguagens onde existem atributos privados, você pode acessá-los através de algum tipo de biblioteca de reflexão / introspecção. E as pessoas fazem muito isso, em frameworks e para solucionar necessidades urgentes. O problema é que as bibliotecas de introspecção são apenas uma maneira difícil de fazer o que você poderia fazer com atributos públicos.
Como Python é uma linguagem muito dinâmica, é contraproducente adicionar esse fardo às suas classes.
O problema não está sendo possível ver - está sendo necessário ver
Para um Pythonista, encapsulamento não é a incapacidade de ver o interior das classes, mas a possibilidade de evitar olhar para ele. O que quero dizer é que o encapsulamento é a propriedade de um componente que permite que ele seja usado sem que o usuário se preocupe com os detalhes internos. Se você pode usar um componente sem se preocupar com sua implementação, então ele é encapsulado (na opinião de um programador Python).
Agora, se você escreveu sua classe de tal forma que pode usá-la sem ter que pensar nos detalhes de implementação, não há problema se você quiser olhar dentro da classe por algum motivo. A questão é: sua API deve ser boa e o resto são detalhes.
O guido disse que sim
Bem, isso não é polêmico: ele disse isso, na verdade . (Procure por "quimono aberto".)
Isso é cultura
Sim, existem alguns motivos, mas nenhum motivo crítico. Este é principalmente um aspecto cultural da programação em Python. Francamente, poderia ser o contrário também - mas não é. Além disso, você poderia facilmente perguntar o contrário: por que algumas linguagens usam atributos privados por padrão? Pelo mesmo motivo principal da prática do Python: porque é a cultura dessas linguagens, e cada escolha tem vantagens e desvantagens.
Como já existe essa cultura, é recomendável segui-la. Caso contrário, você ficará irritado com os programadores Python dizendo para remover o __
do seu código quando fizer uma pergunta no Stack Overflow :)
Primeiro - Qual é o nome mutilado?
A mutilação de nome é invocada quando você está em uma definição de classe e usa
__any_name
ou__any_name_
, isto é, dois (ou mais) sublinhados iniciais e no máximo um sublinhado final.E agora:
O uso ostensivo é evitar que os subclasses usem um atributo que a classe usa.
Um valor potencial é evitar conflitos de nomes com subclasses que desejam substituir o comportamento, de modo que a funcionalidade da classe pai continue funcionando conforme o esperado. No entanto, o exemplo na documentação do Python não é substituível por Liskov, e nenhum exemplo vem à mente onde eu achei isso útil.
As desvantagens são que ele aumenta a carga cognitiva para ler e entender uma base de código, especialmente durante a depuração, onde você vê o nome de sublinhado duplo na origem e um nome mutilado no depurador.
Minha abordagem pessoal é evitá-lo intencionalmente. Eu trabalho em uma base de código muito grande. Os raros usos dela se destacam como uma ferida no polegar e não parecem justificados.
Você precisa estar ciente disso para saber quando vir.
PEP 8
PEP 8 , o guia de estilo da biblioteca padrão do Python, atualmente diz (resumido):
Como funciona?
Se você preceder dois sublinhados (sem terminar dois sublinhados) em uma definição de classe, o nome será mutilado e um sublinhado seguido pelo nome da classe será acrescentado ao objeto:
Observe que os nomes só serão mutilados quando a definição da classe for analisada:
Além disso, aqueles que são novos em Python às vezes têm problemas para entender o que está acontecendo quando não conseguem acessar manualmente um nome que vêem definido em uma definição de classe. Esta não é uma razão forte contra isso, mas é algo a se considerar se você tiver um público que aprende.
Um sublinhado?
Quando minha intenção é que os usuários mantenham suas mãos longe de um atributo, eu tendo a usar apenas o sublinhado, mas isso é porque no meu modelo mental, os subclasses teriam acesso ao nome (o que eles sempre têm, pois podem facilmente identificar o nome mutilado de qualquer maneira).
Se eu estivesse revisando o código que usa o
__
prefixo, perguntaria por que eles estão invocando a mutilação de nomes, e se eles não poderiam fazer tão bem com um único sublinhado, tendo em mente que se os subclasses escolherem os mesmos nomes para a classe e atributo de classe, haverá uma colisão de nomes, apesar disso.fonte
Eu não diria que a prática produz um código melhor. Os modificadores de visibilidade apenas o distraem da tarefa em questão e, como um efeito colateral, forçam sua interface a ser usada conforme pretendido. De modo geral, impor visibilidade evita que os programadores bagunçam as coisas se não tiverem lido a documentação corretamente.
Uma solução muito melhor é a rota que o Python incentiva: suas classes e variáveis devem ser bem documentadas e seu comportamento, claro. A fonte deve estar disponível. Esta é uma maneira muito mais extensível e confiável de escrever código.
Minha estratégia em Python é esta:
Acima de tudo, deve ficar claro o que tudo faz. Documente se outra pessoa for usá-lo. Documente se quiser que seja útil daqui a um ano.
Como uma observação lateral, você realmente deveria usar protected nessas outras linguagens: você nunca sabe que sua classe pode ser herdada mais tarde e para que ela pode ser usada. É melhor proteger apenas as variáveis que você tem certeza que não podem ou não devem ser usadas por código estrangeiro.
fonte
Você não deve começar com dados privados e torná-los públicos conforme necessário. Em vez disso, você deve começar descobrindo a interface do seu objeto. Ou seja, você deve começar descobrindo o que o mundo vê (as coisas públicas) e então descobrir quais coisas privadas são necessárias para que isso aconteça.
Outras linguagens tornam difícil tornar privado o que antes era público. Ou seja, vou quebrar muitos códigos se tornar minha variável privada ou protegida. Mas com propriedades em python, esse não é o caso. Em vez disso, posso manter a mesma interface, mesmo reorganizando os dados internos.
A diferença entre _ e __ é que o python realmente faz uma tentativa de impor o último. Claro, não é realmente difícil, mas torna-se difícil. Tendo _ apenas informando a outros programadores qual é a intenção, eles estão livres para ignorar por sua conta e risco. Mas ignorar essa regra às vezes é útil. Os exemplos incluem depuração, hacks temporários e trabalho com código de terceiros que não foi criado para ser usado da maneira como você o usa.
fonte
Já existem muitas respostas boas para isso, mas vou oferecer outra. Isso também é parcialmente uma resposta às pessoas que continuam dizendo que o sublinhado duplo não é privado (realmente é).
Se você olhar para Java / C #, ambos possuem private / protected / public. Todos esses são construções em tempo de compilação . Eles são aplicados apenas no momento da compilação. Se você fosse usar reflexão em Java / C #, poderia acessar facilmente o método privado.
Agora, toda vez que você chama uma função em Python, está inerentemente usando reflexão. Esses pedaços de código são os mesmos em Python.
A sintaxe do "ponto" é apenas um açúcar sintático para a última parte do código. Principalmente porque usar getattr já é feio com apenas uma chamada de função. Só fica pior a partir daí.
Então, com isso, não pode haver uma versão Java / C # de private, já que Python não compila o código. Java e C # não podem verificar se uma função é privada ou pública em tempo de execução, pois essa informação se foi (e ele não tem conhecimento de onde a função está sendo chamada).
Agora, com essa informação, o nome mutilado do sublinhado duplo faz mais sentido para alcançar "privacidade". Agora, quando uma função é chamada a partir da instância 'self' e percebe que ela começa com '__', ela apenas executa o nome mutilado ali. É apenas mais açúcar sintático. Esse açúcar sintático permite o equivalente a 'privado' em uma linguagem que só usa reflexão para acesso de membro de dados.
Isenção de responsabilidade: nunca ouvi ninguém do desenvolvimento Python dizer algo assim. A verdadeira razão para a falta de "privado" é cultural, mas você também perceberá que a maioria das linguagens de script / interpretadas não tem privado. Um privado estritamente aplicável não é prático em nada, exceto em tempo de compilação.
fonte
Primeiro: por que você deseja ocultar seus dados? Por que isso é tão importante?
Na maioria das vezes você realmente não quer fazer isso, mas o faz porque os outros estão fazendo.
Se você realmente realmente não quer que as pessoas usem algo, adicione um sublinhado na frente disso. É isso ... Pythonistas sabem que coisas com um sublinhado não têm garantia de funcionar todas as vezes e podem mudar sem você saber.
É assim que vivemos e estamos bem com isso.
Usar dois sublinhados tornará sua classe tão ruim para subclasse que mesmo você não vai querer trabalhar dessa maneira.
fonte
A resposta escolhida explica bem como as propriedades eliminam a necessidade de atributos privados , mas eu também acrescentaria que as funções no nível do módulo eliminam a necessidade de métodos privados .
Se você transformar um método em uma função no nível do módulo, você remove a oportunidade das subclasses de substituí-lo. Mover algumas funcionalidades para o nível de módulo é mais Pythônico do que tentar ocultar métodos com alteração de nome.
fonte
O seguinte snippet de código explicará todos os casos diferentes:
sem sublinhado (a)
imprimir todos os atributos válidos do objeto de teste
Aqui, você pode ver que o nome de __a foi alterado para _Test__a para evitar que essa variável seja substituída por qualquer uma das subclasses. Este conceito é conhecido como "Name Mangling" em python. Você pode acessar isso desta forma:
Da mesma forma, no caso de _a, a variável serve apenas para avisar ao desenvolvedor que ela deve ser usada como variável interna daquela classe, o interpretador python não fará nada mesmo que você acesse, mas não é uma boa prática.
uma variável pode ser acessada de qualquer lugar, é como uma variável de classe pública.
Espero que a resposta tenha ajudado você :)
fonte
À primeira vista, deve ser o mesmo que para outras linguagens (em "outros", quero dizer Java ou C ++), mas não é.
Em Java, você tornou privadas todas as variáveis que não deveriam ser acessíveis externamente. Ao mesmo tempo, em Python, você não pode conseguir isso, pois não há "privacidade" (como diz um dos princípios do Python - "Somos todos adultos"). Então sublinhado duplo significa apenas "Pessoal, não use este campo diretamente". O mesmo significado tem sublinhado único, que ao mesmo tempo não causa dor de cabeça quando você tem que herdar de uma classe considerada (apenas um exemplo de possível problema causado por sublinhado duplo).
Portanto, eu recomendo que você use um único sublinhado por padrão para membros "privados".
fonte
"Em caso de dúvida se uma variável deve ser privada ou protegida, é melhor ir com privada." - sim, o mesmo vale para Python.
Algumas respostas aqui falam sobre 'convenções', mas não fornecem os links para essas convenções. O guia oficial para Python, PEP 8 afirma explicitamente:
A distinção entre público e privado e alteração de nomes em Python foram consideradas em outras respostas. Do mesmo link,
fonte