1. ホーム
  2. python

[解決済み] Pythonのクラスの__dict__.__dict__属性とは何ですか?

2022-12-02 20:47:09

質問

>>> 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__ . 何 この <attribute '__dict__' of 'A' objects> で見つかった A.__dict__.__dict__ は、いつ、どのようなものを含むのでしょうか?

どのように解決するのですか?

まずはじめに A.__dict__.__dict__ とは異なり A.__dict__['__dict__'] . 前者は存在せず、後者は __dict__ の属性は、そのクラスのインスタンスが持っているはずのものです。これはデータ記述子オブジェクトで、特定のインスタンスの属性の内部辞書を返します。要するに __dict__ 属性は、オブジェクトの __dict__ に格納できないため、クラスで定義された記述子を介してアクセスすることになります。

これを理解するためには 記述子プロトコルのドキュメント .

短いバージョンです。

  1. インスタンスの場合 a クラスの A へのアクセスは a.__dict__ へのアクセスは A.__dict__['__dict__'] と同じである vars(A)['__dict__'] .
  2. クラスの場合 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__ も同じですが、明らかな理由で二番目のステップをスキップします。

は不可能なので __dict__ をそれ自身に格納することは不可能なので、代わりに記述子プロトコルを介して直接アクセスし、インスタンスの特別なフィールドに格納されます。

同様のシナリオはクラスにも当てはまりますが、彼らの __dict__ は特別なプロキシオブジェクトで、辞書のふりをし (しかし内部的にはそうではないかもしれません)、それを変更したり別のものに置き換えたりすることは許可されていません。このプロキシによって、とりわけ、クラスに固有で、そのベースの 1 つで定義されていないクラスの属性にアクセスすることができます。

デフォルトでは vars(cls) は3つの記述子を持ちます。 __dict__ インスタンスの属性を格納するためのものです。 __weakref__ で内部的に使用される weakref__doc__ は、クラスのdocstringです。を定義すると、最初の二つは消えてしまうかもしれません。 __slots__ . そうすると __dict____weakref__ 属性を使用する代わりに、各スロットに 1 つのクラス属性を設定します。インスタンスの属性は辞書に保存されず、クラス内のそれぞれの記述子によってアクセスすることになります。


そして最後に、矛盾しているのは A.__dict__ とは異なる A.__dict__['__dict__'] は、属性 __dict__ は、例外的に は決して で検索されます。 vars(A) というように、この属性に当てはまることは、実質的に他のどの属性にも当てはまらないのです。例えば A.__weakref__A.__dict__['__weakref__'] . この矛盾がなければ A.__dict__ を使ってもうまくいかないでしょうし、常に vars(A) を使用しなければなりません。