Thursday, January 5, 2012

__dict__ and vars()

vars() is the lesser-known and arguably more Pythonic version of the __dict__ attribute (available on all classes that do not use slots). From the docs:
vars([object])

Without an argument, act like locals().

With a module, class or class instance object as argument (or anything else that has a __dict__ attribute), return that attribute.


As core Python contributor Raymond Hettinger points out on Twitter:
"Most folks prefer len(s) to s.__len__(), prefer next(it) to it.next(), but forget to use vars(s) rather than s.__dict__"


However, I think there's room to argue that s.__dict__ may be a little clearer than vars(s). After all, (almost) everything in Python is an object, and very nearly all objects are backed by dicts. Furthermore, s.__dict__ is faster:

>>> from timeit import timeit
>>> timeit('object.__dict__;object.__dict__')
0.2776460647583008
>>> timeit('vars(object);vars(object)')
1.276643991470337
>>>

Four million iterations later, we see that grabbing the __dict__ is over four and a half times faster. This should actually come as no surprise: accessing built-in functions (like len()/vars()/etc.) is always slower than object attribute access.

4 comments:

  1. So, are you going to use x.__len__() now instead of len(x)? :-P

    ReplyDelete
    Replies
    1. len(x) is faster than x.__len__()
      (function calling instead of attribute reading + function calling)

      Delete
  2. accessing built-in functions (like len()/vars()/etc.) is always slower than object attribute access.
    Nope. Mark Lutz in "Learning Python" writes than len(s) is faster than s.__len__ and simple test confirms that

    ReplyDelete
  3. >>> from timeit import timeit
    >>> timeit('object.__dict__;object.__dict__')
    0.1925686479999058
    >>> timeit('vars(object);vars(object)')
    0.3935023110000202

    Python 3.7.1 on OS X

    ReplyDelete