2011-02-02 13 views
55
>>> 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__にありますが、それに何かが含まれていますか?Pythonクラスの__dict __.__ dict__属性は何ですか?

+6

より適切な例変数は 'ive'でした。少なくともそれはもっと '' .__ dict __ ['ive'] '質問になりました;)私は自分自身を見るでしょう – Joakim

答えて

77

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

これを理解するには、documentation of the descriptor protocolを読んでください。

ショートバージョン:

  1. クラスAinstance.__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__記述子は、この辞書へのアクセスを実装します。、x.__dict__['name']type(x).name.__get__(x, type(x))type(x).name

  • x.__dict__は同じことを行いますが、それはinstance__dict__には不可能だとして、明白な理由
  • のための最初の1をスキップ:

    • x.nameは、順序でそれらを試みると同等ですインスタンスの__dict__に格納され、代わりに直接記述子プロトコルを介してアクセスされ、インスタンス内の特別なフィールドに格納されます。

      __dict__は辞書になりすまして(内部ではないかもしれない)特別なプロキシオブジェクトですが、それを変更したり別のものに置き換えたりすることはできませんが、同様のシナリオがクラスに当てはまります。このプロキシを使用すると、他のすべてのクラスの属性にアクセスすることができます。クラスの属性にアクセスできます。 weakrefによって内部的に使用されるインスタンスの属性、__weakref__を記憶するため__dict__、およびクラスのドキュメント文字列 - デフォルト

      、空のクラスのvars(cls)は、3つのディスクリプタを運びます。 __slots__を定義した場合、最初の2つは消えている可能性があります。次に、__dict____weakref__の属性はありませんが、代わりに各スロットに1つのクラス属性があります。インスタンスの属性は辞書に格納されず、クラスへのアクセスはクラス内のそれぞれの記述子によって提供されます。


      そして最後に、属性__dict__であるためA.__dict__A.__dict__['__dict__']とは異なることに矛盾がある、例外によって、vars(A)に見上げていないので、それは事実上、他のために本当ではないため、真のものです決してあなたが使用する属性。たとえば、A.__weakref__A.__dict__['__weakref__']と同じものです。この矛盾が存在しない場合は、A.__dict__を使用するとうまくいかず、代わりにvars(A)を使用する必要があります。

    +5

    詳細な回答ありがとうございます。私はそれを数回読まなければならなかったが、私はPythonの多くの新しいディテールを学んだので、しばらくしていると思う。 – porgarmingduod

    7

    A.__dict__は、A属性を格納している辞書であるため、A.__dict__['__dict__']は同じA.__dict__属性への直接参照です。

    A.__dict__は、それ自身への(種類の)参照を含んでいます。 「種類」の部分は、式A.__dict__が通常のdictの代わりにdictproxyを返す理由です。すべてA.__dict__.__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' 
    
    +5

    ' A .__ dict __ ['__ dict __'] 'は' A .__ dict__ '。インスタンスの '__dict__'属性を実装しています。 'A __ dict __ ['__ dict __'] .__ get __(A()、A)'はA()の属性を返し、A __ dict __ ['__ dict __'] .__ get __(A、タイプ) 'が失敗します。 –

    5

    いくつか検討してみましょう!

    >>> A.__dict__['__dict__'] 
    <attribute '__dict__' of 'A' objects> 
    

    私はそれが何であるのだろうか?

    >>> type(A.__dict__['__dict__']) 
    <type 'getset_descriptor'> 
    

    getset_descriptorオブジェクトにはどのような属性がありますか?そのdictproxyのコピーを作成することにより

    >>> type(A.__dict__["__dict__"]).__dict__ 
    <dictproxy object at 0xb7efc4ac> 
    

    我々は、具体的__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__を参照できるオブジェクトです。あなたがこのの多くを理解するために、以下の簡単な例を試すことができます

    +0

    PEP 252では、 '__objclass__'はこの属性を定義したクラスであり、そのクラスの属性ではありません。これはあなたの 'getattr'の例を誤ってしまいます。より正確なものは 'getattr(A().__ dict __ ['__ dict __'] .__ objclass__、A .__ dict __ ['__ dict __'] .__ name __)' –

    4

    >>> 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 
    
    関連する問題