Есть ли разница между dir(…)
и vars(…).keys()
в Python?
(Надеюсь, что есть разница, потому что иначе это нарушит принцип "один способ сделать это"...:)
Есть ли разница между dir(…)
и vars(…).keys()
в Python?
(Надеюсь, что есть разница, потому что иначе это нарушит принцип "один способ сделать это"...:)
Объекты 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 начнется с поиска m в x.__dict__
, но он не найдет его. Тем не менее, он знает, что x
является экземпляром C
, поэтому он будет выглядеть в C.__dict__
, найти его там и вызвать m
с x
в качестве первого аргумента.
Таким образом, разница между 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']
В документации есть что сказать о 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__'])
Помимо ответов, я хотел бы добавить, что использование vars() с экземплярами встроенных типов даст ошибку, поскольку экземпляры builtin types не имеют атрибута __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