为什么使用切片[:]比使用明显的方式更快地复制列表?

wim*_*wim 14 python performance cpython list shallow-copy

为什么使用切片对列表进行浅层复制比使用list内置更快?

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
Run Code Online (Sandbox Code Playgroud)

通常当我看到这样奇怪的事情时,它们在python3中被修复 - 但这种差异仍然存在:

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
Run Code Online (Sandbox Code Playgroud)

ndp*_*dpu 9

区别在于额外的函数调用(只是与额外的堆栈操作SLICE+0对比):CALL_FUNCTION 1

>>> 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 
Run Code Online (Sandbox Code Playgroud)

来自dis docs:

SLICE + 0()
实现TOS = TOS [:].

(TOS - 堆栈顶部)

CALL_FUNCTION(argc)
调用函数.argc的低字节表示位置参数的数量,高字节表示关键字参数的数量.在堆栈上,操作码首先查找关键字参数.对于每个关键字参数,该值位于键的顶部.在关键字参数下方,位置参数位于堆栈上,最右侧的参数位于顶部.在参数下面,要调用的函数对象在堆栈上.弹出所有函数参数,并将函数本身从堆栈中弹出,并推送返回值.