Question

Why is shallow-copying a list using a slice so much faster than using list builtin?

In [1]: x = range(10)

In [2]: timeit x_ = x[:]
10000000 loops, best of 3: 83.2 ns per loop

In [3]: timeit x_ = list(x)
10000000 loops, best of 3: 147 ns per loop

Usually when I see weird things like this, they're fixed in python3 - but this discrepancy is still there:

In [1]: x = list(range(10))

In [2]: timeit x_ = x[:]
10000000 loops, best of 3: 100 ns per loop

In [3]: timeit x_ = list(x)
10000000 loops, best of 3: 178 ns per loop
Was it helpful?

Solution

The difference is in additional function call (just SLICE+0 vs CALL_FUNCTION 1 with extra stack operations):

>>> import dis
>>> def f(lst):
...  return lst[:]
... 
>>> def f1(lst):
...  return list(lst)
... 
>>> dis.dis(f)
  2           0 LOAD_FAST                0 (lst)
              3 SLICE+0             
              4 RETURN_VALUE        
>>> dis.dis(f1)
  2           0 LOAD_GLOBAL              0 (list)
              3 LOAD_FAST                0 (lst)
              6 CALL_FUNCTION            1
              9 RETURN_VALUE 

From dis docs:

SLICE+0()
Implements TOS = TOS[:].

(TOS - top of stack)

CALL_FUNCTION(argc)
Calls a function. The low byte of argc indicates the number of positional parameters, the high byte the number of keyword parameters. On the stack, the opcode finds the keyword parameters first. For each keyword argument, the value is on top of the key. Below the keyword parameters, the positional parameters are on the stack, with the right-most parameter on top. Below the parameters, the function object to call is on the stack. Pops all function arguments, and the function itself off the stack, and pushes the return value.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top