まず第一に、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)。