Estou fazendo assim:
def set_property(property,value):
def get_property(property):
ou
object.property = value
value = object.property
Eu sou novo no Python, por isso ainda estou explorando a sintaxe e gostaria de alguns conselhos para fazer isso.
python
getter-setter
Jorge Guberte
fonte
fonte
._x
(que não são uma propriedade, apenas um atributo comum) ignoram oproperty
empacotamento. Somente referências para.x
passar peloproperty
.O caminho "pitônico" não é usar "getters" e "setters", mas usar atributos simples, como demonstra a pergunta, e
del
para excluir (mas os nomes são alterados para proteger os inocentes ... embutidos):Se, posteriormente, você desejar modificar a configuração e obter, poderá fazê-lo sem precisar alterar o código do usuário, usando o comando
property
decorador:(Cada uso do decorador copia e atualiza o objeto de propriedade anterior, observe que você deve usar o mesmo nome para cada conjunto, obter e excluir função / método.
Após definir o acima, a configuração original, obtendo e excluindo o código é a mesma:
Você deve evitar isso:
Em primeiro lugar, o acima não funciona, porque você não fornece um argumento para a instância em que a propriedade seria configurada para (geralmente
self
), que seria:Em segundo lugar, isso duplica o objetivo de dois métodos especiais,
__setattr__
e__getattr__
.Em terceiro lugar, também temos as funções
setattr
egetattr
builtin.O
@property
decorador é para criar getters e setters.Por exemplo, podemos modificar o comportamento da configuração para colocar restrições no valor que está sendo definido:
Em geral, queremos evitar o uso de
property
e apenas usar atributos diretos.É o que se espera dos usuários de Python. Seguindo a regra da menor surpresa, você deve tentar dar a seus usuários o que eles esperam, a menos que você tenha uma razão muito convincente para o contrário.
Demonstração
Por exemplo, digamos que precisávamos que o atributo protegido do nosso objeto fosse um número inteiro entre 0 e 100, inclusive, e evite sua exclusão, com mensagens apropriadas para informar o usuário sobre o uso adequado:
(Observe que
__init__
se refere a,self.protected_value
mas os métodos de propriedade se referemself._protected_value
. Isso é feito para__init__
usar a propriedade por meio da API pública, garantindo que ela esteja "protegida".)E uso:
Os nomes importam?
Sim eles fazem .
.setter
e.deleter
faça cópias da propriedade original. Isso permite que as subclasses modifiquem adequadamente o comportamento sem alterar o comportamento no pai.Agora, para que isso funcione, você deve usar os respectivos nomes:
Não tenho certeza de onde isso seria útil, mas o caso de uso é se você deseja uma propriedade get, set e / ou delete-only. Provavelmente é melhor manter semanticamente a mesma propriedade com o mesmo nome.
Conclusão
Comece com atributos simples.
Se, posteriormente, você precisar de funcionalidade em torno da configuração, obtenção e exclusão, adicione-a com o decorador de propriedades.
Evite funções nomeadas
set_...
eget_...
- é para isso que servem as propriedades.fonte
__init__
método se refere a,self.protected_value
mas o getter e setter se referemself._protected_value
. Poderia explicar como isso funciona? Testei seu código e ele funciona como está - portanto, não é um erro de digitação.__init__
mesma?self.protected_value = start_protected_value
estava realmente chamando a função setter; Eu pensei que era uma tarefa.fonte
O uso
@property
e@attribute.setter
ajuda você a não apenas usar a maneira "pitônica", mas também para verificar a validade dos atributos ao criar o objeto e ao alterá-lo.Com isso, você realmente 'esconde' o
_name
atributo dos desenvolvedores do cliente e também realiza verificações no tipo de propriedade do nome. Observe que, seguindo esta abordagem, mesmo durante a iniciação, o setter é chamado. Assim:Levará a:
Mas:
fonte
Confira o
@property
decorador .fonte
Você pode usar acessadores / mutadores (ie
@attr.setter
e@property
) ou não, mas o mais importante é ser consistente!Se você estiver usando
@property
para simplesmente acessar um atributo, por exemplo,use-o para acessar todos os * atributos! Seria uma má prática acessar alguns atributos usando
@property
e deixar outras propriedades públicas (ou seja, nome sem sublinhado) sem um acessador, por exemplo , nãoObserve que
self.b
não há um acessador explícito aqui, mesmo que seja público.Da mesma forma com os levantadores (ou mutadores ), fique à vontade para usar,
@attribute.setter
mas seja consistente! Quando você faz, por exemploÉ difícil para mim adivinhar sua intenção. Por um lado, você está dizendo que ambos
a
eb
são públicos (sem sublinhado principal em seus nomes); portanto, teoricamente eu deveria ter permissão para acessar / alterar (obter / definir) ambos. Mas então você especifica apenas um mutador explícito paraa
, o que me diz que talvez eu não deva ser capaz de definirb
. Como você forneceu um mutador explícito, não tenho certeza se a falta de accessor explícito (@property
) significa que eu não deveria poder acessar nenhuma dessas variáveis ou você estava simplesmente sendo frugal em usá-lo@property
.* A exceção é quando você deseja explicitamente tornar algumas variáveis acessíveis ou mutáveis, mas não as duas, ou deseja executar alguma lógica adicional ao acessar ou alterar um atributo. É quando estou usando pessoalmente
@property
e@attribute.setter
(caso contrário, não há acessores / mutadores explícitos para atributos públicos).Por fim, as sugestões do PEP8 e do Guia de Estilo do Google:
PEP8, Designing for Herança, diz:
Por outro lado, de acordo com as Regras / Propriedades da linguagem Python do Guia de Estilo do Google, a recomendação é:
Os profissionais dessa abordagem:
e contras:
fonte
@property
, fazer o resto também usar@property
parece uma péssima decisão.@property
(por exemplo, executar alguma lógica especial antes de retornar um atributo). Caso contrário, por que você decoraria um atributo com@propery
e não outros?@property
lateral, não deveria estar usando para começar, certo? Se o seu getter éreturn this._x
e seu setter éthis._x = new_x
, então usar@property
é meio bobo.@property
é ser consistente".Você pode usar os métodos mágicos
__getattribute__
e__setattr__
.Esteja ciente de que
__getattr__
e__getattribute__
não é o mesmo.__getattr__
é invocado apenas quando o atributo não é encontrado.fonte