>>> class A(object): pass
...
>>> A.__dict__
<dictproxy object at 0x173ef30>
>>> A.__dict__.__dict__
Traceback (most recent call last):
File "<string>", line 1, in <fragment>
AttributeError: 'dictproxy' object has no attribute '__dict__'
>>> A.__dict__.copy()
{'__dict__': <attribute '__dict__' of 'A' objects> ... }
>>> A.__dict__['__dict__']
<attribute '__dict__' of 'A' objects> # What is this object?
私が行った場合 A.something = 10
、これはA.__dict__
。 is this <attribute '__dict__' of 'A' objects>
で見つかりましたA.__dict__.__dict__
、およびいつ何かが含まれますか?
まず、A.__dict__.__dict__
はA.__dict__['__dict__']
とは異なり、前者は存在しません。後者は、クラスのインスタンスが持つ__dict__
属性です。特定のインスタンスの属性の内部辞書を返す記述子オブジェクトです。つまり、オブジェクトの__dict__
属性はオブジェクトの__dict__
に格納できないため、クラスで定義された記述子を介してアクセスされます。
これを理解するには、 記述子プロトコルのドキュメント を読む必要があります。
ショートバージョン:
A
のインスタンスの場合、instance.__dict__
へのアクセスはA.__dict__['__dict__']
によって提供されます。これはvars(A)['__dict__']
と同じです。A.__dict__
へのアクセスは、type.__dict__['__dict__']
(理論上)によって提供されます。これはvars(type)['__dict__']
と同じです。ロングバージョン:
クラスとオブジェクトは両方とも、属性演算子(クラスまたはメタクラスの__getattribute__
を介して実装)と、vars(ob)
で使用される__dict__
属性/プロトコルの両方を介して属性へのアクセスを提供します。
通常のオブジェクトの場合、__dict__
オブジェクトは属性を格納する別のdict
オブジェクトを作成し、__getattribute__
は最初にそれにアクセスして属性を取得しようとします(検索を試みる前に)記述子プロトコルを使用して、__getattr__
)を呼び出す前に、クラスの属性。クラスの__dict__
記述子は、この辞書へのアクセスを実装します。
x.name
は、x.__dict__['name']
、type(x).name.__get__(x, type(x))
、type(x).name
を順番に試すのと同じです。x.__dict__
は同じことを行いますが、明白な理由で最初のコードをスキップします__dict__
of instance
をインスタンスの__dict__
に保存することは不可能なので、代わりに記述子プロトコルを介して直接アクセスし、インスタンスの特別なフィールドに保存します。
同様のシナリオはクラスにも当てはまりますが、__dict__
は辞書のふりをする特別なプロキシオブジェクトですが(内部的にはそうでない場合があります)、変更したり別のものに置き換えたりすることはできません。このプロキシを使用すると、他のすべてのクラスの中で、そのベースの1つで定義されていないクラス固有のクラスの属性にアクセスできます。
デフォルトでは、空のクラスのvars(cls)
は、インスタンスの属性を格納する__dict__
、weakref
によって内部的に使用される__weakref__
、およびクラス。 __slots__
を定義すると、最初の2つはなくなる可能性があります。その場合、__dict__
および__weakref__
属性はありませんが、代わりに各スロットに1つのクラス属性があります。インスタンスの属性はディクショナリに保存されず、クラス内のそれぞれの記述子によってそれらへのアクセスが提供されます。
そして最後に、A.__dict__
がA.__dict__['__dict__']
と異なるという矛盾は、属性__dict__
が例外としてnevervars(A)
で検索したため、実際に使用する他の属性には当てはまりません。たとえば、A.__weakref__
はA.__dict__['__weakref__']
と同じものです。この矛盾が存在しない場合、A.__dict__
を使用しても機能せず、代わりにvars(A)
を常に使用する必要があります。
A.__dict__
はA
属性を格納する辞書であるため、A.__dict__['__dict__']
は同じA.__dict__
属性への直接参照です。
A.__dict__
には、それ自体への(種類の)参照が含まれています。 「種類」の部分は、式A.__dict__
が通常のdictproxy
の代わりにdict
を返す理由です。
>>> class B(object):
... "Documentation of B class"
... pass
...
>>> B.__doc__
'Documentation of B class'
>>> B.__dict__
<dictproxy object at 0x00B83590>
>>> B.__dict__['__doc__']
'Documentation of B class'
探索してみましょう!
>>> A.__dict__['__dict__']
<attribute '__dict__' of 'A' objects>
何だろう?
>>> type(A.__dict__['__dict__'])
<type 'getset_descriptor'>
getset_descriptor
オブジェクトにはどのような属性がありますか?
>>> type(A.__dict__["__dict__"]).__dict__
<dictproxy object at 0xb7efc4ac>
そのdictproxy
のコピーを作成することにより、いくつかの興味深い属性、特に__objclass__
および__name__
を見つけることができます。
>>> A.__dict__['__dict__'].__objclass__, A.__dict__['__dict__'].__name__
(<class '__main__.A'>, '__dict__')
__objclass__
はA
への参照であり、__name__
は単なる文字列'__dict__'
であり、属性の名前でしょうか?
>>> getattr(A.__dict__['__dict__'].__objclass__, A.__dict__['__dict__'].__name__) == A.__dict__
True
そこにある! A.__dict__['__dict__']
は、A.__dict__
を参照し直すことができるオブジェクトです。
次の簡単な例を試して、これをさらに理解してください。
>>> class A(object): pass
...
>>> a = A()
>>> type(A)
<type 'type'>
>>> type(a)
<class '__main__.A'>
>>> type(a.__dict__)
<type 'dict'>
>>> type(A.__dict__)
<type 'dictproxy'>
>>> type(type.__dict__)
<type 'dictproxy'>
>>> type(A.__dict__['__dict__'])
<type 'getset_descriptor'>
>>> type(type.__dict__['__dict__'])
<type 'getset_descriptor'>
>>> a.__dict__ == A.__dict__['__dict__'].__get__(a)
True
>>> A.__dict__ == type.__dict__['__dict__'].__get__(A)
True
>>> a.__dict__ == type.__dict__['__dict__'].__get__(A)['__dict__'].__get__(a)
True
上記の例から、クラスオブジェクトの属性はクラスによって保存され、クラスの属性はクラスによって保存されているようです。これはメタクラスです。これは以下によっても検証されます。
>>> a.__dict__ == A.__getattribute__(a, '__dict__')
True
>>> A.__dict__ == type.__getattribute__(A, '__dict__')
True