0Pricing
Python Academy · Leçon

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 ... 42

Descripteurs 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)   # data

Signature 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   # AttributeError

Les 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 function

Descripteur 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__ = fset

Ordre 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 AttributeError

Vé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

  1. Comment les classes Python sont créées
  2. Écrire des métaclasses personnalisées
  3. Descripteurs : __get__, __set__, __delete__
  4. __slots__ et optimisation de la mémoire
← Retour à Python Academy