Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is copying a list using a slice[:] faster than using the obvious way?

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
like image 290
wim Avatar asked Apr 01 '14 20:04

wim


1 Answers

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.

like image 150
ndpu Avatar answered Oct 20 '22 12:10

ndpu