En primer lugar es diferente de A.__dict__.__dict__
A.__dict__['__dict__']
, y el primero no existe. Este último es el atributo __dict__
que las instancias de la clase tendrían. Es un objeto descriptor que devuelve el diccionario interno de atributos para la instancia específica. En resumen, el atributo __dict__
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ías que leer el documentation of the descriptor protocol.
La versión corta:
- Para una instancia de clase
A
, el acceso a instance.__dict__
es proporcionado por A.__dict__['__dict__']
que es el mismo que vars(A)['__dict__']
.
- Para la clase A, el acceso a
A.__dict__
se proporciona por type.__dict__['__dict__']
(en teoría) que es el mismo que vars(type)['__dict__']
.
La versión larga:
Ambas clases y objetos proporcionan acceso a los atributos tanto a través del operador de atributo (implementado a través de la clase o metaclase de __getattribute__
), y la __dict__
atributo/protocolo que se utiliza por vars(ob)
.
Para los objetos normales, el objeto __dict__
crea una dict
objeto separado, que almacena los atributos, y __getattribute__
primeros intentos de acceder a ella y obtener los atributos de allí (antes de intentar buscar el atributo en la clase utilizando el descriptor protocolo, y antes de llamar al __getattr__
). El descriptor __dict__
en 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 se salta el primero por razones obvias
Como es imposible que el __dict__
de instance
a se almacenará en __dict__
de la instancia, se accede directamente a través del protocolo de descriptor y se almacena en un campo especial en la instancia.
Un escenario similar es cierto para las clases, aunque su __dict__
es un objeto proxy especial que pretende ser un diccionario (pero puede que no sea internamente) y no le permite cambiarlo o reemplazarlo por otro. Este proxy le permite, entre todo lo demás, acceder a los atributos de una clase que son específicos de ella y no están definidos en una de sus bases.
Por defecto, un vars(cls)
de una clase vacía lleva tres descriptores - __dict__
para almacenar los atributos de los casos, __weakref__
que se utiliza internamente por weakref
, y la cadena de documentación de la clase. Los primeros dos podrían desaparecer si define __slots__
. Entonces no tendrías los atributos __dict__
y __weakref__
, sino que tendrías un único atributo de clase para cada ranura. Los atributos de la instancia no se almacenarán en un diccionario, y los descriptores respectivos de la clase proporcionarán acceso a ellos.
Y, por último, la inconsistencia que A.__dict__
es diferente de A.__dict__['__dict__']
es porque el atributo __dict__
es, por excepción, no ha buscado en el vars(A)
, así que lo que es verdad porque no es cierto para prácticamente cualquier otra atributo que usarías. Por ejemplo, A.__weakref__
es lo mismo que A.__dict__['__weakref__']
. Si esta incoherencia no existiera, usar A.__dict__
no funcionaría, y en su lugar siempre tendría que usar vars(A)
.
Una variable de ejemplo más adecuada hubiera sido 'ive'. Al menos que hubiera hecho esto un mayor 'Un .__ dict __ [ 'ive']' pregunta;) Voy a ver a mi misma – Joakim