1. ホーム
  2. python

Pythonのdir()と__dict__の最大の違いは何ですか?

2023-11-09 22:36:15

疑問点

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

を出力します。

{}

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

self.__dict__に'f'がないのはなぜか?

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

dir() は、検索するよりもはるかに多くの __dict__

まず最初に dir() のような属性を使用する方法を知っている API メソッドです。 __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']

多くの組み込み型にも同じことが言えます。 list には __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() メソッドでは これらの __dict__ 属性があります。 にあるものは object で、インスタンス、クラス、そしてそのクラスのすべての祖先で利用可能な属性の完全なリストを作成します。

クラスに属性を設定すると、インスタンスはこれらも見ることができます。

>>> 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__ はそのインスタンスの属性の 'ローカル' セットであり、インスタンスで利用可能なすべての属性を含んでいるわけではありません。代わりに、クラスとクラスの継承ツリーも見る必要があります。