Respostas:
Propriedades são um tipo especial de atributo. Basicamente, quando o Python encontra o seguinte código:
spam = SomeObject()
print(spam.eggs)
parece-se eggs
em spam
, em seguida, examina eggs
para ver se ele tem uma __get__
, __set__
ou __delete__
método - se isso acontecer, é uma propriedade. Se for uma propriedade, em vez de apenas retornar o eggs
objeto (como seria para qualquer outro atributo), ele chamará o __get__
método (desde que estávamos fazendo pesquisa) e retornará o que esse método retornar.
Mais informações sobre o modelo de dados e descritores do Python .
Com uma propriedade, você tem controle total sobre seus métodos getter, setter e deleter, que você não possui (se não estiver usando advertências) com um atributo.
class A(object):
_x = 0
'''A._x is an attribute'''
@property
def x(self):
'''
A.x is a property
This is the getter method
'''
return self._x
@x.setter
def x(self, value):
"""
This is the setter method
where I can check it's not assigned a value < 0
"""
if value < 0:
raise ValueError("Must be >= 0")
self._x = value
>>> a = A()
>>> a._x = -1
>>> a.x = -1
Traceback (most recent call last):
File "ex.py", line 15, in <module>
a.x = -1
File "ex.py", line 9, in x
raise ValueError("Must be >= 0")
ValueError: Must be >= 0
x
. Mão única. Se o usuário da classe descobrir sobre _x, eles o usarão por sua conta e risco.
Em termos gerais, uma propriedade e um atributo são a mesma coisa. No entanto, existe um decorador de propriedades no Python que fornece acesso ao getter / setter a um atributo (ou outros dados).
class MyObject(object):
# This is a normal attribute
foo = 1
@property
def bar(self):
return self.foo
@bar.setter
def bar(self, value):
self.foo = value
obj = MyObject()
assert obj.foo == 1
assert obj.bar == obj.foo
obj.bar = 2
assert obj.foo == 2
assert obj.bar == obj.foo
A propriedade permite que você obtenha e defina valores como faria com atributos normais, mas abaixo existe um método chamado de conversão para um getter e setter para você. É realmente apenas uma conveniência reduzir o clichê de chamar getters e setters.
Digamos, por exemplo, que você teve uma aula que realizou algumas coordenadas xey para algo que você precisava. Para defini-los, você pode fazer algo como:
myObj.x = 5
myObj.y = 10
É muito mais fácil olhar e pensar do que escrever:
myObj.setX(5)
myObj.setY(10)
O problema é: e se um dia sua classe mudar de forma que você precise compensar x e y por algum valor? Agora você precisaria alterar sua definição de classe e todo o código que a chama, o que poderia ser realmente demorado e propenso a erros. A propriedade permite que você use a sintaxe anterior, oferecendo a flexibilidade de alterar o último.
No Python, você pode definir getters, setters e excluir métodos com a função de propriedade Se você deseja apenas a propriedade read, também existe um decorador @property que você pode adicionar acima do seu método.
Eu aprendi duas diferenças no site de Bernd Klein, em resumo:
1. Propriedade é uma maneira mais conveniente de encapsular dados.
ex: se você tem um atributo público de comprimento de objeto, mais tarde, seu projeto exige que você o encapsule, ou seja: mude para privado e forneça getter e setter => você precisará alterar muitos dos códigos que escreveu antes:
#Old codes
obj1.length=obj1.length+obj2.length
#New codes(Using private attibutes and getter and setter)
obj1.set_lenght(obj1.get_length()+obj2.get_length()) #=> this is ugly
Se você usar @property e @ lenght.setter =>, não precisará alterar esses códigos antigos
2. Uma propriedade pode encapsular vários atributos
class Person:
def __init__(self, name, physic_health, mental_health):
self.name=name
self.__physic_health=physic_health #physic_health is real value in range [0, 5.0]
self.__mental_health=mental_health #mental_health is real value in range [0, 5.0]
@property
def condition(self):
health=self.__physic_health+self.__mental_health
if(health<5.0):
return "I feel bad!"
elif health<8.0:
return "I am ok!"
else:
return "Great!"
Neste exemplo, __physic_health
e __mental_health
são privados e não podem ser acessados diretamente de fora, a única maneira de a classe externa interagir com eles é através da propriedadecondition
Também há uma diferença não óbvia que eu uso para armazenar em cache ou atualizar dados; geralmente, temos uma função conectada ao atributo de classe. Por exemplo, eu preciso ler o arquivo uma vez e manter o conteúdo atribuído ao atributo para que o valor seja armazenado em cache:
class Misc():
def __init__(self):
self.test = self.test_func()
def test_func(self):
print 'func running'
return 'func value'
cl = Misc()
print cl.test
print cl.test
Resultado:
func running
func value
func value
Acessamos o atributo duas vezes, mas nossa função foi acionada apenas uma vez. Alterar o exemplo acima para usar a propriedade fará com que o valor do atributo seja atualizado sempre que você o acessar:
class Misc():
@property
def test(self):
print 'func running'
return 'func value'
cl = Misc()
print cl.test
print cl.test
Resultado:
func running
func value
func running
func value