Prima di tutto A.__dict__.__dict__è diverso da A.__dict__['__dict__'], e il primo non esiste. Quest'ultimo è l' __dict__attributo che avrebbero le istanze della classe. È un oggetto descrittore che restituisce il dizionario interno degli attributi per l'istanza specifica. In breve, l' __dict__attributo di un oggetto non può essere memorizzato negli oggetti __dict__, quindi vi si accede tramite un descrittore definito nella classe.
Per capirlo, dovresti leggere il documentazione del protocollo del descrittore .
La versione breve:
- Per un'istanza di classe
A, l'accesso a instance.__dict__è fornito daA.__dict__['__dict__'] che è lo stesso di vars(A)['__dict__'].
- Per la classe A, l'accesso a
A.__dict__è fornito da type.__dict__['__dict__'](in teoria) che è lo stesso di vars(type)['__dict__'].
La versione lunga:
Sia le classi che gli oggetti forniscono l'accesso agli attributi sia tramite l'operatore di attributo (implementato tramite la classe o la metaclasse __getattribute__), sia l' __dict__attributo / protocollo utilizzato da vars(ob).
Per gli oggetti normali, l' __dict__oggetto crea un dictoggetto separato , che memorizza gli attributi, e __getattribute__prima cerca di accedervi e di ottenere gli attributi da lì (prima di tentare di cercare l'attributo nella classe utilizzando il protocollo del descrittore e prima di chiamare __getattr__). Il __dict__descrittore sulla classe implementa l'accesso a questo dizionario.
x.nameè equivalente a cercare quelli in ordine: x.__dict__['name'], type(x).name.__get__(x, type(x)),type(x).name
x.__dict__ fa lo stesso ma salta il primo per ovvi motivi
Come è impossibile per la __dict__di instanceessere conservato in__dict__ dell'istanza, si accede attraverso il protocollo descrittore direttamente invece, ed è memorizzato in un campo speciale nel caso.
Uno scenario simile è vero per le classi, sebbene il loro __dict__ sia uno speciale oggetto proxy che finge di essere un dizionario (ma potrebbe non esserlo internamente) e non consente di modificarlo o sostituirlo con un altro. Questo proxy ti consente, tra tutte le altre, di accedere agli attributi di una classe che sono specifici per essa e non definiti in una delle sue basi.
Per impostazione predefinita, a vars(cls)di una classe vuota trasporta tre descrittori: __dict__per memorizzare gli attributi delle istanze, __weakref__che viene utilizzato internamente da weakref, e la docstring della classe. I primi due potrebbero essere spariti se definisci __slots__. Quindi non avresti attributi __dict__e __weakref__, ma avresti invece un singolo attributo di classe per ogni slot. Gli attributi dell'istanza quindi non verrebbero memorizzati in un dizionario e l'accesso ad essi sarà fornito dai rispettivi descrittori nella classe.
Infine, l'incongruenza che A.__dict__è diversa da A.__dict__['__dict__']è perché l'attributo __dict__, per eccezione, non è mai stato cercato vars(A), quindi ciò che è vero per non è vero praticamente per qualsiasi altro attributo che useresti. Ad esempio, A.__weakref__è la stessa cosa di A.__dict__['__weakref__']. Se questa incoerenza non esistesse, l'utilizzo A.__dict__non funzionerebbe e dovresti sempre usarla vars(A).
ive. Almeno avrebbe reso questa unaA.__dict__['ive']domanda più ;) Ci vedremo fuori