Gostaria de entender como a função property
interna funciona . O que me confunde é que property
também pode ser usado como um decorador, mas ele só aceita argumentos quando usado como uma função interna e não quando usado como um decorador.
Este exemplo é da documentação :
class C(object):
def __init__(self):
self._x = None
def getx(self):
return self._x
def setx(self, value):
self._x = value
def delx(self):
del self._x
x = property(getx, setx, delx, "I'm the 'x' property.")
property
Os argumentos de getx
, setx
, delx
e uma série doc.
No código abaixo property
é usado como decorador. O objetivo disso é ox
função, mas no código acima não há lugar para uma função de objeto nos argumentos.
class C(object):
def __init__(self):
self._x = None
@property
def x(self):
"""I'm the 'x' property."""
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
E, como é o x.setter
e x.deleter
decoradores criado? Estou confuso.
property
é realmente uma classe (não uma função), embora provavelmente chame o__init__()
método quando você cria um objeto, é claro. Usando ahelp(property)
partir do terminal é perspicaz.help
também é uma aula por algum motivo.Respostas:
A
property()
função retorna um objeto descritor especial :É este objeto que possui métodos extras :
Estes agem como decoradores também . Eles retornam um novo objeto de propriedade:
isso é uma cópia do objeto antigo, mas com uma das funções substituídas.
Lembre-se de que a
@decorator
sintaxe é apenas açúcar sintático; a sintaxe:realmente significa a mesma coisa que
então
foo
a função é substituída porproperty(foo)
, que vimos acima é um objeto especial. Então, quando você usa@foo.setter()
, o que você está fazendo é chamar issoproperty().setter
método que mostrei acima, que retorna uma nova cópia da propriedade, mas desta vez com a função setter substituída pelo método decorado.A sequência a seguir também cria uma propriedade completa, usando esses métodos do decorador.
Primeiro, criamos algumas funções e um
property
objeto com apenas um getter:Em seguida, usamos o
.setter()
método para adicionar um setter:Por último, adicionamos um deleter com o
.deleter()
método:Por último, mas não menos importante, o
property
objeto atua como um objeto descritor , para que ele tenha.__get__()
,.__set__()
e.__delete__()
métodos para ligar para atributo de instância recebendo, a criação e exclusão de:O Descriptor Howto inclui uma implementação de amostra Python pura do
property()
tipo:fonte
Foo.prop = prop
pode fazerFoo().prop = 5; pront Foo().prop; del Foo().prop
o resultado desejado.type()
como acesso a atributos e métodos Dunder, para serem usados como pontos de extensão pelas funções e operadores padrão.@human.name.getter
alterasse oproperty
objeto no local em vez de retornar um novo, ohuman.name
atributo seria alterado, alterando o comportamento dessa superclasse.A documentação diz que é apenas um atalho para criar propriedades somente leitura. assim
é equivalente a
fonte
@property
como decorador em sua classe.Aqui está um exemplo mínimo de como
@property
pode ser implementado:Caso contrário,
word
permanece um método em vez de uma propriedade.fonte
self.word = my_word
- o que, em seguida, trabalhar da mesma formaprint( Thing('ok').word ) = 'ok'
Thing('ok').word
chama a função internamente em tempo de execução?A primeira parte é simples:
é o mesmo que
property
com apenas um getter.O próximo passo seria estender essa propriedade com um setter e um deleter. E isso acontece com os métodos apropriados:
retorna uma nova propriedade que herda tudo do antigo
x
mais o setter fornecido.x.deleter
funciona da mesma maneira.fonte
O seguinte:
É o mesmo que:
É o mesmo que:
É o mesmo que:
Qual é o mesmo que:
fonte
Abaixo está outro exemplo de como
@property
ajudar quando é necessário refatorar o código que é retirado daqui (apenas o resumo abaixo):Imagine que você criou uma classe
Money
como esta:e um usuário cria uma biblioteca dependendo dessa classe em que ele usa, por exemplo
Agora, vamos supor que você decida alterar sua
Money
classe e se livrar dos atributosdollars
e,cents
mas decida rastrear apenas a quantidade total de centavos:Se o usuário acima mencionado agora tentar executar sua biblioteca como antes
isso resultará em um erro
Isso significa que agora todo mundo que confia na sua
Money
classe original precisaria alterar todas as linhas de código ondedollars
ecents
usadas, o que pode ser muito doloroso ... Então, como isso pode ser evitado? Usando@property
!É assim que:
quando agora chamamos da nossa biblioteca
funcionará como esperado e não tivemos que alterar uma única linha de código em nossa biblioteca! De fato, nem precisaríamos saber que a biblioteca da qual dependemos mudou.
Também
setter
funciona bem:Você
@property
também pode usar em classes abstratas; Eu dou um exemplo mínimo aqui .fonte
self.dollar = dollars
? fizemos muito com @property, mas parece que nenhuma funcionalidade de extração foi adicionada.Li todas as postagens aqui e percebi que podemos precisar de um exemplo da vida real. Por que, na verdade, temos @property? Portanto, considere um aplicativo Flask no qual você usa o sistema de autenticação. Você declara um usuário modelo em
models.py
:Nesse código, nós "escondemos" o atributo
password
usando o@property
que aciona aAttributeError
asserção quando você tenta acessá-lo diretamente, enquanto usamos @ property.setter para definir a variável de instância realpassword_hash
.Agora
auth/views.py
, podemos instanciar um usuário com:Atributo de aviso
password
que vem de um formulário de registro quando um usuário preenche o formulário. A confirmação da senha acontece no front end comEqualTo('password', message='Passwords must match')
(no caso de você estar se perguntando, mas é um formulário diferente do Flask relacionado ao tópico).Espero que este exemplo seja útil
fonte
Este ponto foi esclarecido por muitas pessoas lá em cima, mas aqui está um ponto direto que eu estava procurando. Acho que é importante começar pelo decorador @property. por exemplo:-
A chamada da função "get_config ()" funcionará assim.
Se você notar que não usei colchetes "()" para chamar a função. Esta é a coisa básica que eu estava procurando pelo decorador @property. Para que você possa usar sua função como uma variável.
fonte
Vamos começar com os decoradores de Python.
Um decorador Python é uma função que ajuda a adicionar algumas funcionalidades adicionais a uma função já definida.
No Python, tudo é um objeto. Funções em Python são objetos de primeira classe, o que significa que podem ser referenciadas por uma variável, adicionadas nas listas, passadas como argumentos para outra função etc.
Considere o seguinte trecho de código.
Aqui, podemos dizer que a função decorador modificou nossa função say_hello e acrescentou algumas linhas de código extras.
Sintaxe Python para decorador
Vamos concluir tudo do que com um cenário de caso, mas antes disso vamos falar sobre alguns princípios do oops.
Getters e setters são usados em muitas linguagens de programação orientadas a objetos para garantir o princípio do encapsulamento de dados (é visto como o agrupamento de dados com os métodos que operam nesses dados).
Esses métodos são, obviamente, o getter para recuperar os dados e o setter para alterar os dados.
De acordo com esse princípio, os atributos de uma classe são privados para ocultar e protegê-los de outro código.
Sim, @property é basicamente uma maneira pitônica de usar getters e setters.
O Python possui um ótimo conceito chamado property, que simplifica muito a vida de um programador orientado a objetos.
Vamos supor que você decida fazer uma aula que possa armazenar a temperatura em graus Celsius.
Código refatorado, veja como poderíamos ter conseguido isso com propriedade.
No Python, property () é uma função interna que cria e retorna um objeto de propriedade.
Um objeto de propriedade possui três métodos, getter (), setter () e delete ().
Aqui,
poderia ter sido quebrado como,
Ponto a observar:
Agora você pode acessar o valor da temperatura escrevendo.
Podemos continuar adiante e não definir os nomes get_temperature e set_temperature , pois são desnecessários e poluir o namespace da classe.
A maneira pitônica de lidar com o problema acima é usar @property .
Pontos a serem observados -
Como você pode ver, o código é definitivamente menos elegante.
Agora, vamos falar sobre um cenário prático da vida real.
Digamos que você tenha projetado uma classe da seguinte maneira:
Agora, vamos supor que nossa classe ficou popular entre os clientes e eles começaram a usá-la em seus programas. Eles fizeram todos os tipos de atribuições ao objeto.
E um dia fatídico, um cliente confiável veio até nós e sugeriu que "x" deve ser um valor entre 0 e 1000, esse é realmente um cenário horrível!
Devido às propriedades, é fácil: criamos uma versão de propriedade de "x".
Isso é ótimo, não é: você pode começar com a implementação mais simples que se possa imaginar e poderá migrar posteriormente para uma versão de propriedade sem precisar alterar a interface! Portanto, as propriedades não são apenas um substituto para getters e setter!
Você pode verificar esta implementação aqui
fonte
property
é uma classe por trás@property
decorador.Você sempre pode verificar isso:
Reescrevi o exemplo de
help(property)
para mostrar que a@property
sintaxeé funcionalmente idêntico à
property()
sintaxe:Não há diferença em como usamos a propriedade, como você pode ver.
Para responder à pergunta, o
@property
decorador é implementado viaproperty
classe.Então, a questão é explicar
property
um pouco a classe. Está linha:Foi a inicialização. Podemos reescrevê-lo assim:
O significado de
fget
,fset
efdel
:A próxima imagem mostra os trigêmeos que temos, da classe
property
:__get__
,__set__
E__delete__
estão lá para ser substituído . Esta é a implementação do padrão descritor em Python.Também pode usar a propriedade
setter
,getter
edeleter
métodos para ligar a função à propriedade. Veja o próximo exemplo. O métodos2
da classeC
definirá a propriedade duplicada .fonte
Uma propriedade pode ser declarada de duas maneiras.
Você pode dar uma olhada em alguns exemplos que escrevi sobre propriedades em python .
fonte
A melhor explicação pode ser encontrada aqui: Python @Property Explained - Como usar e quando? (Exemplos completos) de Selva Prabhakaran | 5 de novembro de 2018
Isso me ajudou a entender POR QUE não apenas COMO.
https://www.machinelearningplus.com/python/python-property/
fonte
Aqui está outro exemplo:
Basicamente, o mesmo que o exemplo C (objeto), exceto que estou usando x em vez disso ... Eu também não inicializo em __init - ... bem ... sim, mas ele pode ser removido porque __x é definido como parte da classe....
A saída é:
e se eu comentar o self.x = 1234 no init , a saída é:
e se eu definir o _default = None como _default = 0 na função getter (como todos os getters devem ter um valor padrão, mas não são passados pelos valores de propriedade do que vi, para que você possa defini-lo aqui, e na verdade, não é ruim porque você pode definir o padrão uma vez e usá-lo em qualquer lugar), por exemplo: def x (self, _default = 0):
Nota: A lógica getter existe apenas para que o valor seja manipulado por ele para garantir que ele seja manipulado por ele - o mesmo para as instruções de impressão ...
Nota: Estou acostumado a Lua e sou capaz de criar dinamicamente mais de 10 auxiliares quando chamo uma única função e criei algo semelhante para Python sem usar propriedades e funciona até certo ponto, mas, mesmo que as funções estejam sendo criadas antes sendo usado, ainda há problemas às vezes em serem chamados antes da criação, o que é estranho, pois não é codificado dessa maneira ... Prefiro a flexibilidade das meta-tabelas Lua e o fato de poder usar setters / getters reais em vez de acessar diretamente diretamente uma variável ... Eu gosto da rapidez com que algumas coisas podem ser criadas com o Python - por exemplo, programas de GUI. embora uma que estou projetando possa não ser possível sem muitas bibliotecas adicionais - se eu a codifico no AutoHotkey, posso acessar diretamente as chamadas de dll de que preciso, e o mesmo pode ser feito em Java, C #, C ++,
Nota: O código de saída deste fórum está quebrado - eu tive que adicionar espaços à primeira parte do código para que ele funcionasse - ao copiar / colar, assegure-se de converter todos os espaços em abas .... Eu uso abas para Python, porque em um arquivo com 10.000 linhas, o tamanho do arquivo pode ser de 512 KB a 1 MB com espaços e de 100 a 200 KB com guias, o que equivale a uma enorme diferença no tamanho do arquivo e redução no tempo de processamento ...
As guias também podem ser ajustadas por usuário - portanto, se você preferir 2 espaços de largura, 4, 8 ou o que for possível, significa que é útil para desenvolvedores com déficit de visão.
Nota: Todas as funções definidas na classe não são recuadas corretamente devido a um erro no software do fórum - certifique-se de recuar se você copiar / colar
fonte
Uma observação: para mim, para o Python 2.x,
@property
não funcionou como anunciado quando não herdei deobject
:mas funcionou quando:
para Python 3, funcionou sempre.
fonte
object
é uma classe de estilo antigo, e as classes de estilo antigo não suportam o protocolo do descritor (que é o queproperty
implementa para funcionar da maneira que funciona). No Python 3, as classes de estilo antigo não existem mais; todas as classes são o que chamamos de classes new-style em Python 2.