まず第一に、A.__dict__.__dict__
とは異なりA.__dict__['__dict__']
ます。前者は存在せず、後者は__dict__
クラスのインスタンスが持つ属性です。これは、特定のインスタンスの属性の内部ディクショナリを返すデータ記述子オブジェクトです。つまり、オブジェクトの__dict__
属性はオブジェクトのに格納できない__dict__
ため、クラスで定義された記述子を介してアクセスされます。
これを理解するには、記述子プロトコルのドキュメントを読む必要があります。
短いバージョン:
a
クラスのインスタンスの場合A
、へのアクセスa.__dict__
はによって提供されます。A.__dict__['__dict__']
これはと同じvars(A)['__dict__']
です。
- クラス
A
の場合、へのアクセスA.__dict__
は(理論的には)によって提供されます。type.__dict__['__dict__']
これは。と同じvars(type)['__dict__']
です。
長いバージョン:
クラスとオブジェクトの両方が、属性演算子(クラスまたはメタクラスを介して実装__getattribute__
)と、__dict__
によって使用される属性/プロトコルの両方を介して属性へのアクセスを提供しますvars(ob)
。
通常のオブジェクトの場合、オブジェクトは属性を格納__dict__
する別のオブジェクトを作成し、最初にそのオブジェクトにアクセスしてそこから属性を取得しようとします(記述子プロトコルを使用してクラス内の属性を検索する前、およびを呼び出す前)。クラスの記述子は、このディクショナリへのアクセスを実装します。dict
__getattribute__
__getattr__
__dict__
a.name
それらを順番に試すのと同じです:(がデータ記述子のtype(a).__dict__['name'].__get__(a, type(a))
場合のみ)、、、。type(a).__dict__['name']
a.__dict__['name']
type(a).__dict__['name'].__get__(a, type(a))
type(a).__dict__['name']
a.__dict__
同じことを行いますが、明らかな理由で2番目のステップをスキップします。
__dict__
インスタンスをそれ自体に格納することは不可能であるため、代わりに記述子プロトコルを介して直接アクセスされ、インスタンスの特別なフィールドに格納されます。
同様のシナリオがクラスにも当てはまりますが、クラスは__dict__
ディクショナリのふりをする特別なプロキシオブジェクトであり(ただし、内部的にはそうではない場合があります)、クラスを変更したり、別のクラスに置き換えたりすることはできません。このプロキシを使用すると、とりわけ、そのプロキシに固有であり、そのベースの1つで定義されていないクラスの属性にアクセスできます。
デフォルトでvars(cls)
は、空のクラスのaには、内部で使用される__dict__
インスタンスの属性を格納するための記述子と、クラスのdocstringの3つの記述子があります。を定義すると、最初の2つがなくなる可能性があります。その場合、属性はありませんが、代わりにスロットごとに1つのクラス属性があります。その場合、インスタンスの属性はディクショナリに格納されず、それらへのアクセスはクラス内のそれぞれの記述子によって提供されます。__weakref__
weakref
__doc__
__slots__
__dict__
__weakref__
そして最後に、とA.__dict__
は異なる不整合A.__dict__['__dict__']
は、属性__dict__
が例外的に検索されないvars(A)
ためです。したがって、実際に使用する他の属性には当てはまりません。たとえば、A.__weakref__
はと同じですA.__dict__['__weakref__']
。この不整合が存在しない場合、を使用してもA.__dict__
機能せず、代わりに常に使用する必要がありますvars(A)
。