Descripteurs : __get__, __set__, __delete__
Implémentez le protocole des descripteurs pour contrôler l’accès aux attributs.
Descripteurs : __get__, __set__, __delete__ est une leçon Python Academy gratuite sur CoddyKit. Ceci est la leçon 3 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Python Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Python Academy comprend 4 leçons au total.
Qu’est-ce qu’un descripteur ?
Un descripteur est un objet qui définit __get__, __set__ ou __delete__ et qui est affecté comme attribut de classe. Python appelle ces méthodes lors de l’accès à l’attribut.
class Descriptor:
def __get__(self, obj, objtype=None):
print(f"__get__ called, obj={obj}")
return 42
class MyClass:
attr = Descriptor()
print(MyClass().attr) # __get__ called ... 42Descripteurs de données ou sans données
Les descripteurs de données définissent __set__ ou __delete__ et sont prioritaires sur le __dict__ de l’instance. Les descripteurs sans données (uniquement __get__) cèdent la priorité à __dict__.
class DataDesc:
def __get__(self, obj, t): return "data"
def __set__(self, obj, val): pass
class NonDataDesc:
def __get__(self, obj, t): return "nondata"
class C:
d = DataDesc()
n = NonDataDesc()
c = C()
c.__dict__["n"] = "instance" # shadows the non-data desc
c.__dict__["d"] = "instance" # does NOT shadow data desc
print(c.n) # instance
print(c.d) # dataSignature de __get__
__get__(self, obj, objtype) : obj est l’instance (ou None lorsque l’attribut est consulté sur la classe) ; objtype est la classe.
class Verbose:
def __get__(self, obj, objtype=None):
if obj is None:
return self # accessed on class
return f"value for {obj!r}"
class Widget:
label = Verbose()
print(Widget.label) # <Verbose object>
print(Widget().label) # value for <Widget object>__set__ et validation
Implémentez __set__(self, obj, value) pour valider ou transformer une valeur avant de la stocker.
class PositiveInt:
def __set_name__(self, owner, name):
self.name = name
def __get__(self, obj, t):
return obj.__dict__.get(self.name)
def __set__(self, obj, val):
if not isinstance(val, int) or val <= 0:
raise ValueError(f"{self.name} must be a positive int")
obj.__dict__[self.name] = val
class Rect:
width = PositiveInt()
height = PositiveInt()
r = Rect()
r.width = 10
# r.width = -1 # ValueError__set_name__
Python 3.6+ appelle __set_name__(owner, name) sur le descripteur lorsqu’il est affecté à une classe, ce qui lui donne accès au nom de son propre attribut.
class Typed:
def __set_name__(self, owner, name):
self.public = name
self.private = "_" + name
def __get__(self, obj, t):
return None if obj is None else getattr(obj, self.private, None)
def __set__(self, obj, val):
setattr(obj, self.private, val)
class User:
name = Typed()
u = User()
u.name = "Alice"
print(u.name) # Alice__delete__ pour supprimer un attribut
Définissez __delete__(self, obj) pour intercepter del obj.attr.
class Protected:
def __set_name__(self, owner, name): self.name = name
def __get__(self, obj, t):
return obj.__dict__.get(self.name)
def __set__(self, obj, v): obj.__dict__[self.name] = v
def __delete__(self, obj):
raise AttributeError(f"Cannot delete {self.name}")
class Config:
host = Protected()
c = Config(); c.host = "localhost"
# del c.host # AttributeErrorLes fonctions sont des descripteurs sans données
Les fonctions implémentent __get__ pour renvoyer une méthode liée lorsqu’elles sont consultées sur une instance. C’est ainsi que fonctionne la liaison des méthodes en Python.
def greet(self):
return f"Hello from {self}"
class C: pass
C.greet = greet
c = C()
print(c.greet()) # Hello from <C object>classmethod et staticmethod sont des descripteurs
classmethod et staticmethod sont des classes de descripteurs intégrées qui encapsulent des fonctions et modifient la valeur renvoyée par __get__.
class MyClass:
@classmethod
def from_string(cls, s):
return cls()
# classmethod.__get__ returns a bound method with cls
# staticmethod.__get__ returns the plain functionDescripteur d’attribut différé
Créez un descripteur qui calcule une valeur une seule fois et la met en cache pour chaque instance.
class LazyAttr:
def __init__(self, func): self.func = func
def __set_name__(self, owner, name): self.name = name
def __get__(self, obj, t):
if obj is None: return self
val = self.func(obj)
obj.__dict__[self.name] = val # shadows descriptor
return val
class Report:
@LazyAttr
def summary(self):
print("computing...")
return "done"
r = Report()
print(r.summary) # computing... done
print(r.summary) # done (cached)property est un descripteur
property est lui-même un descripteur de données implémenté en C. Comprendre les descripteurs vous aide à comprendre le fonctionnement de @property, @classmethod et @staticmethod.
class Circle:
def __init__(self, r): self._r = r
@property
def radius(self): return self._r
@radius.setter
def radius(self, v):
if v < 0: raise ValueError
self._r = v
# property is: property.__get__ = fget, property.__set__ = fsetOrdre de recherche des descripteurs
Ordre de recherche des attributs en Python : 1) descripteurs de données du type (MRO), 2) dictionnaire de l'instance, 3) descripteurs non liés aux données et variables de classe.
# Pseudocode for obj.attr:
# 1. Check type(obj).__mro__ for a data descriptor
# 2. Check obj.__dict__
# 3. Check type(obj).__mro__ for non-data descriptor or class var
# 4. Raise AttributeErrorVérification rapide
Quel type de descripteur a la priorité sur le __dict__ de l'instance ?
Récapitulatif
Les descripteurs interceptent l'accès aux attributs via __get__, __set__ et __delete__. Les descripteurs de données masquent le __dict__ de l'instance ; les descripteurs non liés aux données ne le font pas. Utilisez __set_name__ pour connaître le nom de l'attribut. property, classmethod et staticmethod sont tous des descripteurs.
Questions Fréquemment Posées
La leçon « Descripteurs : __get__, __set__, __delete__ » est-elle gratuite ?
Oui — le texte complet de « Descripteurs : __get__, __set__, __delete__ » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Python Academy, passe à CoddyKit PRO. Le cours Python Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Descripteurs : __get__, __set__, __delete__ » ?
Implémentez le protocole des descripteurs pour contrôler l’accès aux attributs. Tu pratiques Python Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer Python Academy ?
Aucune expérience préalable n'est requise. Python Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 3 sur 4.
Combien de temps prend la leçon « Descripteurs : __get__, __set__, __delete__ » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon Python Academy ?
Oui. Chaque leçon Python Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Comment les classes Python sont créées
- Écrire des métaclasses personnalisées
- Descripteurs : __get__, __set__, __delete__
- __slots__ et optimisation de la mémoire