Is there a difference between dir(…)
and vars(…).keys()
in Python?
(I hope there is a difference, because otherwise this would break the "one way to do it" principle... :)
Is there a difference between dir(…)
and vars(…).keys()
in Python?
(I hope there is a difference, because otherwise this would break the "one way to do it" principle... :)
The documentation has this to say about dir
:
Without arguments, return the list of names in the current local scope. With an argument, attempt to return a list of valid attributes for that object.
And this about vars
:
Without arguments, return a dictionary corresponding to the current local symbol table. With a module, class or class instance object as argument (or anything else that has a
__dict__
attribute), returns a dictionary corresponding to the object’s symbol table.
If you don't see the difference, maybe this will show you more:
>>> 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__']
If you don't feel like reading through that, dir
includes these attributes while vars
does not:
>>> set(dir(list)).difference(vars(list).keys())
set(['__str__', '__reduce__', '__subclasshook__', '__setattr__', '__reduce_ex__'
, '__format__', '__class__', '__delattr__'])
Python objects store their instance variables in a dictionary that belongs to
the object. var(x)
returns this dictionary (as does x.__dict__
). dir(x)
, on the
other hand, returns a dictionary of x
's "attributes, its class's attributes, and
recursively the attributes of its class's base classes."
When you access an object's attribute using the dot operator, python does a lot more than just looking up the attribute in that objects dictionary. A common case is when x is an object of class C and you call a method m on it.
class C(object):
def m(self):
print "m"
x=C()
x.m()
The method m is not stored in x.__dict__
. It is an attribute of the class C.
When you call x.m()
, python will begin by looking for m in x.__dict__
, but it
won't find it. However, it knows that x is an instance of C, so it will next
look in C.__dict__
, find it there, and call m with x as the first argument.
So the difference between vars(x) and dir(x) is that dir(x) does the extra work of looking in x's class (and it's bases) for attributes that are accessible from it, not just those attributes that are stored in x's own symbol table. In the above example, vars(x) returns an empty dictionary, because x has no instance variables. However, dir(x) returns
['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__',
'__hash__', '__init__', '__module__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__str__', '__weakref__', 'm']