La fonction property()
renvoie un objet descripteur spécial:
>>> property()
C'est cet objet qui possède des méthodes supplémentaires :
>>> property().getter
>>> property().setter
>>> property().deleter
Ces méthodes agissent également comme des décorateurs. Elles renvoient un nouvel objet de propriété :
>>> property().getter(None)
qui est une copie de l'ancien objet, mais avec l'une des fonctions remplacée.
N'oubliez pas que la syntaxe @decorator
est juste du sucre syntaxique; la syntaxe :
@property
def foo(self): return self._foo
signifie vraiment la même chose que
def foo(self): return self._foo
foo = property(foo)
ainsi, la fonction foo
est remplacée par property(foo)
, qui, comme nous l'avons vu ci-dessus, est un objet spécial. Ensuite, lorsque vous utilisez @foo.setter()
, ce que vous faites est d'appeler la méthode property().setter
que je vous ai montrée ci-dessus, qui renvoie une nouvelle copie de la propriété, mais cette fois avec la fonction setter remplacée par la méthode décorée.
La séquence suivante crée également une véritable propriété, en utilisant ces méthodes décoratives.
En premier lieu, nous créons quelques fonctions et un objet property
avec seulement un getter:
>>> def getter(self): print('Get!')
...
>>> def setter(self, value): print('Set to {!r}!'.format(value))
...
>>> def deleter(self): print('Delete!')
...
>>> prop = property(getter)
>>> prop.fget is getter
True
>>> prop.fset is None
True
>>> prop.fdel is None
True
Ensuite, nous utilisons la méthode .setter()
pour ajouter un setter:
>>> prop = prop.setter(setter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is None
True
Enfin, nous ajoutons un deleter avec la méthode .deleter()
:
>>> prop = prop.deleter(deleter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is deleter
True
Enfin, l'objet property
agit en tant qu'objet descripteur, donc il possède les méthodes .__get__()
, .__set__()
et .__delete__()
pour se connecter à la récupération, la définition et la suppression d'attributs d'instance :
>>> class Foo: pass
...
>>> prop.__get__(Foo(), Foo)
Get!
>>> prop.__set__(Foo(), 'bar')
Set to 'bar'!
>>> prop.__delete__(Foo())
Delete!
Le Guide Howto des descripteurs inclut une implémentation d'exemple en Python pur du type property()
:
class Property:
"Emuler PyProperty_Type() dans Objects/descrobject.c"
def __init__(self, fget=None, fset=None, fdel=None, doc=None):
self.fget = fget
self.fset = fset
self.fdel = fdel
if doc is None and fget is not None:
doc = fget.__doc__
self.__doc__ = doc
def __get__(self, obj, objtype=None):
if obj is None:
return self
if self.fget is None:
raise AttributeError("attribut illisible")
return self.fget(obj)
def __set__(self, obj, value):
if self.fset is None:
raise AttributeError("impossible de définir l'attribut")
self.fset(obj, value)
def __delete__(self, obj):
if self.fdel is None:
raise AttributeError("impossible de supprimer l'attribut")
self.fdel(obj)
def getter(self, fget):
return type(self)(fget, self.fset, self.fdel, self.__doc__)
def setter(self, fset):
return type(self)(self.fget, fset, self.fdel, self.__doc__)
def deleter(self, fdel):
return type(self)(self.fget, self.fset, fdel, self.__doc__)
28 votes
Voir aussi: Comment fonctionnent les propriétés Python?
6 votes
property
est en fait une classe (pas une fonction), bien qu'elle appelle probablement la méthode__init__()
lorsque vous créez un objet, bien sûr. Utiliserhelp(property)
depuis le terminal est instructif.help
est également une classe pour une raison quelconque.4 votes
Je pense que ce lien offre un bon exemple : [propriété] (journaldev.com/14893/python-property-decorator)
9 votes
@Shule fil de discussion de 2 ans, mais toujours : Tout est une classe. Même les classes.
5 votes
Cela était aussi déroutant pour moi. J'ai finalement trouvé un article qui a pu simplifier les choses pour moi. J'espère que cela aidera quelqu'un d'autre. programiz.com/python-programming/property Je ne suis en aucun cas affilié au site.
0 votes
De nombreuses réponses dans cette discussion expliquent comment fonctionne
@property
, mais ne traitent pas pourquoi vous l'utiliseriez. La question "pourquoi utiliser@property
en Python" est l'équivalent de "pourquoi utiliser des accesseurs (getters/setters/deleters) en Java", car@property
est l'équivalent pythonique du même concept. Ces discussions complémentaires ont quelques discussions utiles stackoverflow.com/questions/1568091/… stackoverflow.com/questions/6618002/…0 votes
Sur l'utilité du décorateur de propriété : betterprogramming.pub/…
0 votes
ici un sujet connexe sur comment implémenter dynamiquement le protocole de descripteurs getter/setter
0 votes
J'ai une question liée à cette question. Dans l'exemple fourni, il y a un attribut protégé
self._x
, qui est protégé. Mais en utilisant la propriété définie ci-dessus, on peut définir et lire l'attribut en tapant simplementc = C(), c.x = 99
permettant ainsi à tous les programmeurs d'utiliser cet attribut comme s'il n'était PAS protégé. J'ai compris comment fonctionne @property. Mais je ne comprends toujours pas quel est l'avantage de l'utiliser dans l'exemple ci-dessus