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}