atributos Python objeto - metodologia para o acesso
-
03-07-2019 - |
Pergunta
Suponha que eu tenho uma classe com alguns atributos. Como é que é melhor (no Pythonic-OOP) sentido para acessar esses atributos? Assim como obj.attr
? Ou talvez write obter acessores?
Quais são os estilos de nomenclatura aceitos para essas coisas?
Editar: Você pode elaborar sobre as melhores práticas de nomear atributos com um único ou duplo sublinhado à esquerda? Eu vejo na maioria dos módulos que um único sublinhado é usado.
Se esta pergunta já foi feita (e eu tenho um palpite que tem, embora a pesquisa não trouxe resultados), aponte para ele por favor -. E eu vou fechar este
Solução
A forma geralmente aceite de fazer as coisas é apenas usando atributos simples, como assim
>>> class MyClass:
... myAttribute = 0
...
>>> c = MyClass()
>>> c.myAttribute
0
>>> c.myAttribute = 1
>>> c.myAttribute
1
Se você achar que precisa de ser capaz de getters escrever e setters, então o que você quer procurar é "propriedades da classe python" e o artigo de Ryan Tomayko em Getters / Setters / Fuxors é um ótimo lugar para começar (embora um pouco longo)
Outras dicas
Com relação às sublinhados individuais e duplos-líder: ambos indicam o mesmo conceito de 'caráter privado'. Ou seja, as pessoas vão saber o atributo (seja um método ou um atributo de dados 'normal' ou qualquer outra coisa) não faz parte da API pública do objeto. As pessoas vão saber que para tocá-lo diretamente é um convite ao desastre.
Além disso, os atributos dupla líder sublinhado (mas não os atributos de liderança de um único sublinhado) são nome-mutilado para tornar o acesso a eles por acidente de subclasses ou em qualquer outro lugar fora da classe atual, menos provável. Você ainda pode acessá-los, mas não tão trivial. Por exemplo:
>>> class ClassA:
... def __init__(self):
... self._single = "Single"
... self.__double = "Double"
... def getSingle(self):
... return self._single
... def getDouble(self):
... return self.__double
...
>>> class ClassB(ClassA):
... def getSingle_B(self):
... return self._single
... def getDouble_B(self):
... return self.__double
...
>>> a = ClassA()
>>> b = ClassB()
Você pode a._single
agora trivialmente acesso e b._single
e se o atributo _single
criado por ClassA
:
>>> a._single, b._single
('Single', 'Single')
>>> a.getSingle(), b.getSingle(), b.getSingle_B()
('Single', 'Single', 'Single')
Mas tentando acessar o atributo __double
na instância a
ou b
diretamente não vai funcionar:
>>> a.__double
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: ClassA instance has no attribute '__double'
>>> b.__double
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: ClassB instance has no attribute '__double'
E embora os métodos definidos no ClassA
pode chegar a ele diretamente (quando chamado em ambos os casos):
>>> a.getDouble(), b.getDouble()
('Double', 'Double')
Os métodos definidos na ClassB
não pode:
>>> b.getDouble_B()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in getDouble_B
AttributeError: ClassB instance has no attribute '_ClassB__double'
E bem nesse erro que você receber uma dica sobre o que está acontecendo. O nome do atributo __double
, quando acessado dentro de uma classe, é ser-nome desconfigurado para incluir o nome da classe que está sendo acessado em . Quando tenta ClassA
ao acesso self.__double
, ele realmente transforma - pelo compiletime - em um acesso de self._ClassA__double
, e da mesma forma para ClassB
. (Se um método em ClassB
foram para atribuir a __double
, não incluído no código para a brevidade, não seria mesmos tocar ClassA
de __double
mas criar um novo atributo.) Não há nenhuma outra proteção deste atributo, assim você ainda pode acessá-lo diretamente se você sabe o nome certo:
>>> a._ClassA__double, b._ClassA__double
('Double', 'Double')
Então, por que este é um problema?
Bem, é um problema qualquer momento você quiser herdar e mudar o comportamento de qualquer negociação código com este atributo. Você quer ter reimplementar tudo o que toca este atributo duplo sublinhado diretamente, ou você tem que adivinhar o nome da classe e mangle o nome manualmente. O problema se agrava quando este atributo duplo sublinhado é na verdade um método: substituindo o método ou chamando o método em uma subclasse significa fazer o nome-desconfiguração manualmente ou reimplementar todo o código que chama o método de não use o nome de duplo sublinhado. Sem mencionar acessando o atributo de forma dinâmica, com getattr()
:. você terá que manualmente mangle lá, também
Por outro lado, porque o atributo só é trivialmente reescrito, ele oferece apenas 'proteção' superficial. Qualquer pedaço de código ainda pode obter no atributo pelo deturpação manualmente, embora que vai fazer sua dependente o nome de código o classe, e os esforços do seu lado para refatorar seu código ou renomear sua classe (enquanto ainda mantém o mesmo nome visível para o usuário, uma prática comum em Python) seria desnecessariamente quebrar seu código. Eles também podem 'truque' Python em fazer o nome-desconfiguração para eles, nomeando sua classe a mesma que a sua: Observe como não há nenhum nome módulo incluído no nome do atributo mutilado. E, por último, o atributo duplo sublinhado ainda é visível em todas as listas de atributos e todas as formas de introspecção que não tomar cuidado para pular atributos que começam com um sublinhado ( única ).
Assim, se você usar nomes de duplo sublinhado, usá-los excessivamente com moderação, como eles podem revelar-se bastante inconveniente, e nunca usá-los para métodos ou qualquer outra coisa que uma subclasse pode sempre querer reimplementar, substituição ou acesso diretamente . E perceber que double-líder sublinhado-desconfiguração nome ofertas sem proteção real . No final, utilizando um único sublinhado levando você ganha tanto e dá-lhe menos (potencial futuro) dor. Use um único sublinhado líder.
Edit: Você pode elaborar sobre as melhores práticas de nomear atributos com um único ou duplo sublinhado à esquerda? Eu vejo na maioria dos módulos que um único sublinhado é usado.
Single sublinhado não faz especial significa nada para python, é apenas melhores práticas, para dizer "ei, você provavelmente não quer acessar este se você não sabe o que está fazendo". sublinhado duplo no entanto faz python mangle o nome fazendo internamente acessível apenas a partir da classe onde ele está definido.
Double esquerda e à direita sublinhado denota uma função especial, como __add__
que é chamado quando usando o operador +.
Leia mais em PEP 8 , especialmente as "Convenções de nomenclatura" seção.
Eu acho que a maioria só acessá-las diretamente, sem necessidade de métodos get / set.
>>> class myclass:
... x = 'hello'
...
>>>
>>> class_inst = myclass()
>>> class_inst.x
'hello'
>>> class_inst.x = 'world'
>>> class_inst.x
'world'
BTW, você pode usar a função dir () para ver o que atribui / métodos estão ligados à sua instância:
>>> dir(class_inst)
['__doc__', '__module__', 'x']
Dois líderes barras inferiores, "__" são usados ??para fazer um atributo ou função privada. Para outras convenções referem-se a PEP 08: http://www.python.org/dev/peps/pep-0008/
Python não precisa definir acessores desde o início, uma vez que a conversão de atributos em propriedades é rápido e indolor. Consulte o seguinte para uma demonstração vívida:
Não há nenhum ponto real de fazer getter / setters em python, você não pode coisas proteção de qualquer maneira e se você precisa executar algum código extra quando obter / definir o olhar imóvel no builtin imóvel () (python -c ' ajuda (propriedade) ')
Algumas pessoas usam getters e setters. Dependendo de qual estilo de codificação que você usa, você pode nomeá-los getSpam e seteggs. Mas você também pode fazer você atributos somente leitura ou atribuir somente. Isso é um pouco estranho para fazer. Uma maneira é substituir o
> __getattr__
e
> __setattr__
métodos.
Editar:
Enquanto a minha resposta ainda é verdade, isso não é certo, como eu vim a perceber. Há maneiras melhores de fazer acessores em python e não são muito estranho.