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 dict
objeto 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.name
es 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 instance
se 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