Primero que nada A.__dict__.__dict__es diferente A.__dict__['__dict__']y el primero no existe. Este último es el __dict__atributo que tendrían las instancias de la clase. Es un objeto descriptor que devuelve el diccionario interno de atributos para la instancia específica. En resumen, el __dict__atributo de un objeto no se puede almacenar en el objeto __dict__, por lo que se accede a través de un descriptor definido en la clase.
Para entender esto, tendría que leer la documentación del protocolo descriptor .
La versión corta:
- Para una instancia de clase
A, el acceso a instance.__dict__es proporcionado por lo A.__dict__['__dict__']que es lo mismo que vars(A)['__dict__'].
- Para la clase A, el acceso a
A.__dict__lo proporciona type.__dict__['__dict__'](en teoría), que es el mismo que vars(type)['__dict__'].
La versión larga:
Tanto las clases como los objetos proporcionan acceso a los atributos tanto a través del operador de atributo (implementado a través de la clase o metaclase __getattribute__) como del __dict__atributo / protocolo que utiliza vars(ob).
Para los objetos normales, el __dict__objeto crea un dictobjeto separado , que almacena los atributos, y __getattribute__primero intenta acceder a él y obtener los atributos desde allí (antes de intentar buscar el atributo en la clase utilizando el protocolo descriptor y antes de llamar __getattr__). El __dict__descriptor de la clase implementa el acceso a este diccionario.
x.namees equivalente a tratar aquellos en orden: x.__dict__['name'], type(x).name.__get__(x, type(x)),type(x).name
x.__dict__ hace lo mismo pero omite el primero por razones obvias
Como es imposible que el __dict__de instancese almacene en __dict__la instancia, se accede a él directamente a través del protocolo descriptor y se almacena en un campo especial en la instancia.
Un escenario similar es cierto para las clases, aunque __dict__hay un objeto proxy especial que pretende ser un diccionario (pero puede que no lo sea internamente) y no le permite cambiarlo o reemplazarlo por otro. Este proxy te permite, entre todo lo demás, acceder a los atributos de una clase que le son específicos y no definidos en una de sus bases.
De forma predeterminada, una vars(cls)de una clase vacía lleva tres descriptores: __dict__para almacenar los atributos de las instancias, __weakref__que se usa internamente weakref, y la cadena de documentos de la clase. Los dos primeros podrían desaparecer si lo define __slots__. Entonces no tendrías atributos __dict__y __weakref__, sino que tendrías un atributo de clase único para cada espacio. Los atributos de la instancia entonces no se almacenarían en un diccionario, y el acceso a ellos será proporcionado por los descriptores respectivos en la clase.
Y, por último, la inconsistencia que A.__dict__es diferente A.__dict__['__dict__']es porque el atributo __dict__, por excepción, nunca se busca vars(A), por lo que lo que es cierto no es cierto para prácticamente cualquier otro atributo que usaría. Por ejemplo, A.__weakref__es lo mismo que A.__dict__['__weakref__']. Si esta inconsistencia no existiera, el uso A.__dict__no funcionaría y tendría que usar siempre en su vars(A)lugar.
ive. Al menos habría hecho de esta unaA.__dict__['ive']pregunta más ;) Me