Un descripteur est un objet qui implémente l'une des méthodes get, set et delete. Il permet de contrôler l'accès aux attributs de la classe.
Méthodes standard du descripteur :
__get__(self, instance, owner)__set__(self, instance, value)__delete__(self, instance)Les descripteurs peuvent être :
Exemple d'utilisation :
class OnlyPositive: def __init__(self): self._name = '_value' def __get__(self, instance, owner): return instance.__dict__[self._name] def __set__(self, instance, value): if value < 0: raise ValueError('Value must be >= 0') instance.__dict__[self._name] = value class Account: value = OnlyPositive() def __init__(self, value): self.value = value acc = Account(10) acc.value = -1 # ValueError!
property n'est qu'un sucre syntaxique pour créer des descripteurs au niveau de la classe.
Que se passe-t-il si l'on crée un descripteur en tant qu'attribut d'instance et non de classe ?
Beaucoup pensent que le descripteur fonctionnera, mais ce n'est pas le cas.
Réponse correcte :
Le descripteur fonctionne uniquement s'il est défini directement en tant qu'attribut de la classe. Si le descripteur est défini en tant qu'attribut d'instance, les méthodes get/set ne seront pas appelées — la logique normale d'accès à l'attribut s'applique.
Histoire
Utilisation de property au lieu d'un vrai descripteur
Pour la validation et d'autres attributs liés, le développeur a utilisé une simple property, ce qui entraînait un doublonnage fréquent de la logique et l'impossibilité de réutiliser le code entre différentes classes.
Histoire
Non-respect de l'immuabilité lors de la réutilisation du stockage
Le descripteur stockait des données dans un attribut interne de sa propre classe (self.x), et non dans le stockage interne de l'instance, ce qui rendait l'attribut "commun", permettant à différentes instances de la classe de se réécrire mutuellement des valeurs — des données "fuiteraient" entre les objets.
Histoire
Confusion entre data descriptor et non-data descriptor
Dans une hiérarchie complexe, l'implémentation de set a été omise, ce qui a entraîné l'écrasement du descripteur par un attribut normal de l'instance, brisant tout le mécanisme de validation — le bug ne se manifestait pas toujours, rendant le débogage difficile.