python中dir和__dict__最大的区别是什么?

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

输出:

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

为什么自我中没有“f”.__ dict__

dir()不仅仅是查找__dict__

首先, dir()是一个API方法,它知道如何使用像__dict__这样的属性来查找对象的属性。

不是所有的对象都有__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'] 

这同样适用于许多内置types; 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上的object来创build实例,类和类的所有祖先上的可用属性的完整列表。

在类上设置属性时,实例也会看到这些:

 >>> 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对象的属性查找遵循从实例到types到父类的对象的层次结构以search属性。

只有在实例上直接设置属性时,才会看到实例的__dict__中反映的属性,而类__dict__保持不变:

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

TLDR; 或摘要

dir()不只是查找一个对象的__dict__ (有时甚至不存在),它将使用该对象的传统(它的类或types,以及该类或types的任何超类或父类)给你所有可用属性的完整图片。

实例__dict__只是该实例上的“本地”属性集合,并不包含实例上可用的每个属性。 相反,您需要查看类和类的inheritance树。

函数f属于类C的字典。 c.__dict__产生特定于实例c属性。

 >>> class C(object): def f(self): print self.__dict__ >>> c = C() >>> c.__dict__ {} >>> ca = 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>}) 

虽然一个对象可以引用它的类的属性(实际上是所有的祖先类),但是被引用的类属性并不会成为关联的字典本身的一部分。 因此,虽然它是合法的访问函数f在类C定义为cf() ,但它不会在c.__dict__作为c的属性出现。

 >>> ca = 1 >>> c.__dict__ {'a': 1}