Le numéro précédent s'arrêtait dès qu'un __dict__ répondait. Certaines réponses ne sont pas des valeurs — ce sont du code.The previous issue stopped as soon as a __dict__ answered. Some answers aren't values — they're code.
Le numéro 16 a réduit obj.x à une recherche dans des __dict__ successifs, qui s'arrête à la première correspondance et la retourne telle quelle. C'est vrai pour un entier, une chaîne, une liste. Ce ne l'est plus si ce qui est trouvé dans le __dict__ de la classe définit une méthode spéciale __get__ : Python n'en retourne alors pas la valeur brute, il l'appelle, et retourne ce que cet appel produit. Un tel objet est un descripteur. property, la façon la plus courante d'en créer un, transforme ainsi un accès qui ressemble à une simple lecture — c.aire — en exécution de code à chaque fois qu'on le lit.Issue 16 reduced obj.x to a search through successive __dict__s, stopping at the first match and returning it as-is. That's true for an int, a string, a list. It stops being true if what's found in the class's __dict__ defines a special method __get__: Python then doesn't return its raw value, it calls it, and returns whatever that call produces. Such an object is a descriptor. property, the most common way to create one, thus turns an access that looks like a plain read — c.aire — into code execution, every single time it's read.
class Cercle: def __init__(self, rayon): self.rayon = rayon @property def aire(self): print("calcul de l'aire...") # une preuve que du CODE s'exécute return 3.14159 * self.rayon ** 2 c = Cercle(5) print(c.aire) # "calcul de l'aire..." puis 78.53975 # c.aire ressemble à un attribut ordinaire -- mais c'est un APPEL DÉGUISÉ
Face à un self.x qui semble anodin, demande : ce nom vit-il comme une simple valeur dans un __dict__, ou comme un objet qui définit __get__ — et donc s'exécute à chaque lecture ?Facing a self.x that looks harmless, ask: does this name live as a plain value in a __dict__, or as an object that defines __get__ — and therefore runs on every read?
len(x) n'est qu'un appel déguisé à x.__len__() — les dunders du numéro 08 reposaient déjà sur cette idée : une syntaxe banale qui cache un appel de méthode spécial. Les descripteurs appliquent exactement le même principe à l'accès attribut lui-même.len(x) is just disguised syntax for x.__len__() — issue 08's dunders already rested on that idea: ordinary syntax hiding a special method call. Descriptors apply the exact same principle to attribute access itself.