7

I've recently looked into using list(), dict(), tuple() in place of [], {}, and (), respectively when needing to create an empty one of of the three. The reasoning is that it seemed more readable. I was going to ask for opinions on the style, but then I decided to test performance. I did this:

>>> from timeit import Timer
>>> Timer('for x in range(5): y = []').timeit()
0.59327821802969538
>>> from timeit import Timer
>>> Timer('for x in range(5): y = list()').timeit()
1.2198944904251618

I tried dict(), tuple() and list() and the function call version of each was incredibly worse than the syntactical version ({} [], ()) So, I have 3 questions:

  1. Why are the function calls more expensive?
  2. Why is there so much difference?
  3. Why the heck does it take 1.2 seconds to create 5 empty lists in my timer? I know timeit turns off garbage collection, but that couldn't possibly have an effect when considering I only used range(5).
Kevin
  • 74,910
  • 12
  • 133
  • 166
orokusaki
  • 55,146
  • 59
  • 179
  • 257
  • re: style opinion - I use [] pretty frequently. I think it's clear enough. The performance question is interesting though. – nmichaels Nov 22 '10 at 02:32
  • there are many things that look weird about python until you get used to them. I would always prefer `[]` to `list()` because `list()` might actually not be `__builtins__.list`. buyer beware. – SingleNegationElimination Nov 22 '10 at 02:39

4 Answers4

19

the function call requires a variable name lookup, followed by a function invocation. the function called then creates a list and returns it. The list syntax literal gets the interpreter to just make a list:

>>> import dis
>>> foo = lambda :[]
>>> bar = lambda :list()
>>> dis.dis(foo)
  1           0 BUILD_LIST               0
              3 RETURN_VALUE        
>>> dis.dis(bar)
  1           0 LOAD_GLOBAL              0 (list)
              3 CALL_FUNCTION            0
              6 RETURN_VALUE        
>>>
SingleNegationElimination
  • 151,563
  • 33
  • 264
  • 304
6

To answer #3.

timeit actually repeats your program 1 000 000 times by default. So in fact, you are creating 5 million lists in 1.2 seconds.

Kugel
  • 19,354
  • 16
  • 71
  • 103
3
  >>> from dis import dis

  >>> dis(lambda: list())
  1           0 LOAD_GLOBAL              0 (list)
              3 CALL_FUNCTION            0
              6 RETURN_VALUE        

  >>> dis(lambda: [])
  1           0 BUILD_LIST               0
              3 RETURN_VALUE        
satoru
  • 31,822
  • 31
  • 91
  • 141
0

Scope lookups are required in order to find dict, tuple, and list, and multiple scopes need to be searched in order to find them. With the syntactic sugar the compiler can know that a specific object needs to be created and so can emit the proper bytecode to do so.

Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358