Python中的dir(...)和vars(...)。keys()之间的区别?


71

有没有之间的差异dir(…),并vars(…).keys()在Python?

(我希望会有区别,因为否则会破坏“一种方法”的原则... :)


11
明确地说,原则是“一种显而易见的方法”,而不是“仅一种方法”。
— 伊桑·弗曼

Answers:


99

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

当您使用点运算符访问对象的属性时,Python所做的不仅仅是在该对象字典中查找该属性。一个常见的情况是whenx是class的实例,C而您调用其方法m:

class C:
    def m(self):
        print("m")
    
x = C()
x.m()

该方法m未存储在中x.__dict__。它是类的一个属性C。

当您调用时x.m(),Python将从min中开始查找x.__dict__,但找不到它。但是,它知道x是的一个实例C,因此它将接下来查找,在其中C.__dict__找到它,并m以x作为第一个参数进行调用。

因此,vars(x)和之间的区别在于,在类的类(及其基类)中查找可以从中访问的属性,而不仅仅是存储在自己的符号表中的那些属性,dir(x)这需要dir(x)做额外的工作。在上面的示例中,由于没有实例变量,因此返回空字典。但是,回报xxvars(x)xdir(x)

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', 
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', 
'__init__', '__init_subclass__', '__le__', '__lt__', '__module__', 
'__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', 
'__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 
'm']

10
我要补充一点的是,它dir()还会返回广告位,而vars()不会返回。
— Eric O Lebigot 2013年

3
也dir可以通过实现__dir__magic方法自定义的输出:class A: def __dir__(self): return ['a']然后您拥有dir(A()) == ['a']while vars(A()) == {}。
— 巴库里

27

该文档的内容dir如下:

不带参数的情况下,返回当前本地范围内的名称列表。使用一个参数,尝试返回该对象的有效属性列表。

关于vars:

不带参数的情况下,返回与当前本地符号表相对应的字典。使用模块,类或类实例对象作为参数(或具有__dict__属性的任何其他对象),返回与该对象的符号表相对应的字典。

如果您看不到差异,则可能会显示更多(分组以便于阅读):

>>> dir(list)
['__add__', '__class__', '__class_getitem__', '__contains__', '__delattr__', 
'__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', 
'__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', 
'__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', 
'__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', 
'__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', 
'__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 
'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
>>> vars(list).keys()
dict_keys(['__repr__', 
'__hash__', 
'__getattribute__', 
'__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', 
'__iter__', 
'__init__', 
'__len__', 
'__getitem__', '__setitem__', '__delitem__', 
'__add__', '__mul__', '__rmul__', '__contains__', '__iadd__', '__imul__', 
'__new__', 
'__reversed__', '__sizeof__', 
'clear', 'copy', 'append', 'insert', 'extend', 'pop', 'remove', 'index', 'count', 'reverse', 'sort', 
'__class_getitem__', 
'__doc__'])

如果您不想通读,请dir在vars不包含以下属性的情况下:

>>> set(dir(list)) - vars(list).keys()
{'__class__', '__delattr__', '__dir__', '__format__', '__init_subclass__', 
'__reduce__', '__reduce_ex__', '__setattr__', '__str__', '__subclasshook__'}

另请注意,dir()的输出按字母顺序排序,而vars()的输出则按定义属性的顺序排序。


4
我猜这里是“符号表”的关键术语。在官方Python文档中很难找到它的定义(实际上,我还没有找到它:)。
— Eric O Lebigot 2011年

2

除了给出的答案外,我还要补充一点,将vars()与实例内置类型一起使用会产生错误,因为实例内置类型没有__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

@SiHa,它实际上是内置类型的实例,没有__dict__属性。感谢您纠正我。我已经更新了答案。
— Mangu Singh Rajpurohit

好点子。同样,实现__slots__的自定义类的实例也没有__dict__属性,并且同样会产生错误。
— Scott H
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.