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 parA.__dict__['__dict__']lequel est identique àvars(A)['__dict__'].
- Pour la classe A, l'accès à A.__dict__est fourni partype.__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 dictobjet 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.nameest é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 instancesoit 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