Why are list(), dict(), and tuple() slower than [], {}, and ()?
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 开发者_如何学Goask 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:
- Why are the function calls more expensive?
- Why is there so much difference?
- 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 usedrange(5)
.
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
>>>
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.
>>> 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
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.
精彩评论