Réponses:
Les propriétés sont un type particulier d'attribut. Fondamentalement, lorsque Python rencontre le code suivant:
spam = SomeObject()
print(spam.eggs)
il recherche eggsdans spamet examine ensuite eggspour voir si elle a __get__, __set__ou __delete__méthode - si elle le fait, il est une propriété. S'il s'agit d' une propriété, au lieu de simplement renvoyer l' eggsobjet (comme pour tout autre attribut), il appellera la __get__méthode (puisque nous faisions la recherche) et retournera tout ce que cette méthode renvoie.
Plus d'informations sur le modèle de données et les descripteurs de Python .
Avec une propriété, vous avez un contrôle complet sur ses méthodes getter, setter et deleter, que vous n'avez pas (si vous n'utilisez pas de mises en garde) avec un attribut.
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. Une manière. Si l'utilisateur de la classe découvre _x, il l'utilise à ses propres risques.
En termes généraux, une propriété et un attribut sont la même chose. Cependant, il existe un décorateur de propriété en Python qui fournit un accès getter / setter à un attribut (ou à d'autres données).
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
La propriété vous permet d'obtenir et de définir des valeurs comme vous le feriez avec des attributs normaux, mais en dessous se trouve une méthode appelée pour la traduire en un getter et un setter pour vous. C'est vraiment juste une commodité de réduire le passe-partout de l'appel des getters et des setters.
Disons, par exemple, que vous aviez une classe qui contenait des coordonnées x et y pour quelque chose dont vous aviez besoin. Pour les définir, vous voudrez peut-être faire quelque chose comme:
myObj.x = 5
myObj.y = 10
C'est beaucoup plus facile à regarder et à penser que d'écrire:
myObj.setX(5)
myObj.setY(10)
Le problème est, que se passe-t-il si un jour votre classe change de telle sorte que vous devez compenser vos x et y d'une certaine valeur? Maintenant, vous devez entrer et modifier la définition de votre classe et tout le code qui l'appelle, ce qui pourrait prendre beaucoup de temps et être source d'erreurs. La propriété vous permet d'utiliser la première syntaxe tout en vous offrant la flexibilité de changement de la seconde.
En Python, vous pouvez définir des getters, des setters et des méthodes de suppression avec la fonction de propriété. Si vous voulez juste la propriété read, il existe également un décorateur @property que vous pouvez ajouter au-dessus de votre méthode.
J'ai appris 2 différences sur le site de Bernd Klein, en résumé:
1. La propriété est un moyen plus pratique d'encapsuler des données.
ex: Si vous avez un attribut public de longueur Object, plus tard, votre projet vous demandera de l'encapsuler, c'est-à-dire: changez-le en privé et fournissez getter et setter => vous devez changer de nombreux codes que vous avez écrits auparavant:
#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
Si vous utilisez @property et @ lenght.setter => vous n'avez pas besoin de changer ces anciens codes
2. Une propriété peut encapsuler plusieurs attributs
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!"
Dans cet exemple, __physic_healthet __mental_healthsont privés et ne sont pas accessibles directement de l'extérieur, le seul moyen d'interagir avec les classes extérieures est via la propriétécondition
Il y a aussi une différence non évidente que j'utilise pour mettre en cache ou actualiser les données, souvent nous avons une fonction connectée à l'attribut de classe. Par exemple, je dois lire le fichier une fois et conserver le contenu attribué à l'attribut afin que la valeur soit mise en 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
Production:
func running
func value
func value
Nous avons accédé à l'attribut deux fois mais notre fonction n'a été déclenchée qu'une seule fois. La modification de l'exemple ci-dessus pour utiliser la propriété entraînera l'actualisation de la valeur de l'attribut chaque fois que vous y accédez:
class Misc():
@property
def test(self):
print 'func running'
return 'func value'
cl = Misc()
print cl.test
print cl.test
Production:
func running
func value
func running
func value