Tout d'abord A.__dict__.__dict__
est différent de A.__dict__['__dict__']
, et le premier n'existe pas. Ce dernier est l' __dict__
attribut qu'auraient les instances de la classe. C'est un objet descripteur qui renvoie le dictionnaire interne des attributs pour l'instance spécifique. En bref, l' __dict__
attribut d'un objet ne peut pas être stocké dans un objet __dict__
, il est donc accessible via un descripteur défini dans la classe.
Pour comprendre cela, vous devez lire la documentation du protocole de descripteur .
La version courte:
- Pour une instance de classe
A
, l'accès à instance.__dict__
est fourni par A.__dict__['__dict__']
lequel est identique à vars(A)['__dict__']
.
- Pour la classe A, l'accès à
A.__dict__
est fourni par type.__dict__['__dict__']
(en théorie) ce qui est identique à vars(type)['__dict__']
.
La version longue:
Les classes et les objets donnent accès aux attributs à la fois via l'opérateur d'attribut (implémenté via la classe ou la métaclasse __getattribute__
) et l' __dict__
attribut / protocole utilisé par vars(ob)
.
Pour les objets normaux, l' __dict__
objet crée un dict
objet séparé , qui stocke les attributs, et __getattribute__
essaie d'abord d'y accéder et d'obtenir les attributs à partir de là (avant d'essayer de rechercher l'attribut dans la classe en utilisant le protocole descripteur, et avant d'appeler __getattr__
). Le __dict__
descripteur de la classe implémente l'accès à ce dictionnaire.
x.name
est équivalent à ceux pour essayer: x.__dict__['name']
, type(x).name.__get__(x, type(x))
,type(x).name
x.__dict__
fait de même mais saute le premier pour des raisons évidentes
Comme il est impossible que le __dict__
of instance
soit stocké dans __dict__
l'instance, il est directement accessible via le protocole de descripteur et est stocké dans un champ spécial de l'instance.
Un scénario similaire est vrai pour les classes, bien que leur __dict__
un objet proxy spécial qui prétend être un dictionnaire (mais peut ne pas l'être en interne), et ne vous permet pas de le modifier ou de le remplacer par un autre. Ce proxy vous permet, entre autres, d'accéder aux attributs d'une classe qui lui sont spécifiques, et non définis dans l'une de ses bases.
Par défaut, une vars(cls)
classe vide porte trois descripteurs - __dict__
pour stocker les attributs des instances, __weakref__
qui sont utilisés en interne par weakref
, et la docstring de la classe. Les deux premiers pourraient avoir disparu si vous définissez __slots__
. Vous n'auriez alors pas d' attributs __dict__
et __weakref__
, mais à la place, vous auriez un attribut de classe unique pour chaque emplacement. Les attributs de l'instance ne seraient alors pas stockés dans un dictionnaire, et leur accès sera fourni par les descripteurs respectifs de la classe.
Et enfin, l'incohérence qui A.__dict__
est différente de A.__dict__['__dict__']
c'est parce que l'attribut __dict__
, par exception, n'est jamais recherché vars(A)
, donc ce qui est vrai car ce n'est pas vrai pour pratiquement tout autre attribut que vous utiliseriez. Par exemple, A.__weakref__
c'est la même chose que A.__dict__['__weakref__']
. Si cette incohérence n'existait pas, l'utilisation A.__dict__
ne fonctionnerait pas et vous devriez toujours utiliser à la vars(A)
place.
ive
. Au moins, cela aurait fait une autreA.__dict__['ive']
question;) Je me verrai dehors