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 :)