2009-06-11 121 views
41

Python中的dir(…)vars(…).keys()之间有区别吗?Python中的dir(...)和vars(...).keys()之间的区别?

(我希望是有区别的,否则这将打破“做到这一点的一种方式”的原则... :)

+8

要明确,原则是“一个*明显的*做到这一点”,而不是“*只有*一种做法”。 – 2011-11-01 00:04:14

+0

@EthanFurman:right :) – EOL 2011-11-01 09:36:31

回答

67

Python对象将其实例变量存储在属于对象的字典中。 vars(x)返回此字典(与x.__dict__一样)。另一方面,dir(x)返回一个字典x的“属性,它的类的属性,递归地它的类的基类的属性。”

当您使用点运算符访问对象的属性时,python所做的不仅仅是查找该对象字典中的属性。常见的情况是当x是类C的对象,并且您调用其上的方法m

class C(object): 
    def m(self): 
     print "m" 

x = C() 
x.m() 

方法m没有存储在x.__dict__。它是类C的一个属性。 当您拨打x.m()时,python将从x.__dict__开始查找m,但不会找到它。但是,它知道xC的一个实例,因此它将接着查看C.__dict__,在那里找到它,并将mx作为第一个参数。

所以vars(x)dir(x)之间的不同之处在于dir(x)确实在x寻找额外工作“是从它访问的类(和其基地)的属性,而不仅仅是那些属性存储在x自己符号表。在上例中,vars(x)返回空字典,因为x没有实例变量。然而,dir(x)回报

['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__', 
'__hash__', '__init__', '__module__', '__new__', '__reduce__', 
'__reduce_ex__', '__repr__', '__setattr__', '__str__', '__weakref__', 'm'] 
+6

我会补充说'dir()`也返回插槽,而'vars()`不会。 – EOL 2013-06-04 13:26:50

23

的文档已经这样说dir

如果没有参数,则返回当前本地作用域中的名称列表。 使用参数尝试返回该对象的有效属性列表。

而这约vars

没有参数,返回对应于当前局部符号表的字典。 使用作为参数的模块,类或类实例对象(或其他任何具有__dict__属性的对象)将返回与该对象的符号表相对应的字典。

如果你没有看到其中的差别,也许这会告诉你更多:

>>> dir(list) 
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__delsli 
ce__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getit 
em__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', 
'__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__r 
educe__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__' 
, '__setitem__', '__setslice__', '__sizeof__', '__str__', '__subclasshook__', 'a 
ppend', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort' 
] 
>>> vars(list).keys() 
['__getslice__', '__getattribute__', 'pop', 'remove', '__rmul__', '__lt__', '__s 
izeof__', '__init__', 'count', 'index', '__delslice__', '__new__', '__contains__ 
', 'append', '__doc__', '__len__', '__mul__', 'sort', '__ne__', '__getitem__', ' 
insert', '__setitem__', '__add__', '__gt__', '__eq__', 'reverse', 'extend', '__d 
elitem__', '__reversed__', '__imul__', '__setslice__', '__iter__', '__iadd__', ' 
__le__', '__repr__', '__hash__', '__ge__'] 

如果你不喜欢通过读书,dir包括这些属性,而vars不会:

>>> set(dir(list)).difference(vars(list).keys()) 
set(['__str__', '__reduce__', '__subclasshook__', '__setattr__', '__reduce_ex__' 
, '__format__', '__class__', '__delattr__']) 
+1

我想这里的“符号表”是关键术语。在官方的Python文档中很难找到它的定义(事实上,我还没有找到:))。 – EOL 2011-04-21 20:17:03

3

除了给出答案,我想补充的是,使用瓦尔()的情况下,内置的类型将给错误,因为实例内建类型没有__dict__属性。

例如。

In [96]: vars([]) 
--------------------------------------------------------------------------- 

TypeError Traceback (most recent call last) 
<ipython-input-96-a6cdd8d17b23> in <module>() 
     ----> 1 vars([]) 
TypeError: vars() argument must have __dict__ attribute