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 dict
oggetto 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 instance
essere 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