web-dev-qa-db-ja.com

pythonのdirと__dict__の最大の違いは何ですか?

class C(object):
    def f(self):
        print self.__dict__
        print dir(self)
c = C()
c.f()

出力:

{}

['__class__', '__delattr__','f',....]

なぜselfに 'f'がないのか。__dict__

60
shellfly

dir()はルックアップ___dict___以上のことを行います

まず、dir()は、___dict___などの属性を使用してオブジェクトの属性を検索する方法を知っているAPIメソッドです。

ただし、すべてのオブジェクトに___dict___属性があるわけではありません。たとえば、カスタムクラスに ___slots___属性 を追加する場合、そのクラスのインスタンスには___dict___属性はありませんが、dir()は、それらのインスタンスで使用可能な属性をリストできます。

_>>> class Foo(object):
...     __slots__ = ('bar',)
...     bar = 'spam'
... 
>>> Foo().__dict__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute '__dict__'
>>> dir(Foo())
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'bar']
_

同じことが多くの組み込み型に当てはまります。 listsには___dict___属性はありませんが、dir()を使用してすべての属性をリストできます。

_>>> [].__dict__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute '__dict__'
>>> dir([])
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__delslice__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__setslice__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
_

インスタンスでdir()が行うこと

Pythonインスタンスには独自の___dict___がありますが、クラスにもあります:

_>>> class Foo(object):
...     bar = 'spam'
... 
>>> Foo().__dict__
{}
>>> Foo.__dict__.items()
[('__dict__', <attribute '__dict__' of 'Foo' objects>), ('__weakref__', <attribute '__weakref__' of 'Foo' objects>), ('__module__', '__main__'), ('bar', 'spam'), ('__doc__', None)]
_

dir()メソッドは、bothこれらの___dict___属性、andobjectにあるもので、インスタンス、クラス、およびクラスのすべての祖先で使用可能な属性の完全なリストを作成します。

クラスに属性を設定すると、インスタンスには次のものも表示されます。

_>>> f = Foo()
>>> f.ham
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute 'ham'
>>> Foo.ham = 'eggs'
>>> f.ham
'eggs'
_

属性がクラス___dict___に追加されるため:

_>>> Foo.__dict__['ham']
'eggs'
>>> f.__dict__
{}
_

インスタンス___dict___が空のままになっていることに注意してください。 Pythonオブジェクトの属性ルックアップは、属性を検索するために、インスタンスからタイプ、親クラスまでのオブジェクトの階層に従います。

インスタンスに属性を直接設定した場合のみ、クラスの___dict___が変更されないまま、インスタンスの___dict___に反映される属性が表示されます。

_>>> f.stack = 'overflow'
>>> f.__dict__
{'stack': 'overflow'}
>>> 'stack' in Foo.__dict__
False
_

TLDR;または概要

dir()はオブジェクトの___dict___(存在しないこともある)を検索するだけでなく、オブジェクトの遺産(そのクラスまたはタイプ、およびスーパークラスまたは親)を使用しますそのクラスまたはタイプ)を使用して、使用可能なすべての属性の完全な画像を提供します。

インスタンス___dict___は、そのインスタンスの「ローカル」属性セットであり、インスタンスで使用可能なすべての属性が含まれているわけではありません。代わりに、クラスとクラスの継承ツリーも調べる必要があります。

111
Martijn Pieters

関数fは、クラスCの辞書に属します。 c.__dict__は、インスタンスcに固有の属性を生成します。

>>> class C(object):
    def f(self):
        print self.__dict__


>>> c = C()
>>> c.__dict__
{}
>>> c.a = 1
>>> c.__dict__
{'a': 1}

C.__dict__は、関数Cを含むクラスfの属性を生成します。

>>> C.__dict__
dict_proxy({'__dict__': <attribute '__dict__' of 'C' objects>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'C' objects>, '__doc__': None, 'f': <function f at 0x0313C1F0>})

オブジェクトはそのクラス(および実際にはすべての祖先クラス)の属性を参照できますが、そのように参照されたクラス属性は関連するdict自体の一部にはなりません。したがって、クラスfc.f()として定義されている関数Cへの正当なアクセスですが、c.__dict__cの属性としては表示されません。

>>> c.a = 1
>>> c.__dict__
{'a': 1}
5
Naveen Kumar