为什么使用切片[:]复制列表比使用常规方法快?

14
为什么使用切片浅拷贝列表比使用内置的 list 函数快得多?
答案: 为什么使用切片浅拷贝列表比使用内置的 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

通常当我遇到像这样奇怪的问题时,它们可以在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

与https://dev59.com/z2cs5IYBdhLWcg3w1XbZ?rq=1相关的编程内容。 - njzk2
一个解释是list是一个需要调用的函数。 - njzk2
同时,还需要列出每个项目的需求清单,其中切片只是将一块内存复制到新地址的操作。 - Joran Beasley
2
事实上,至少对于“[:]”的情况,可能有一种优化方法,可以直接在列表上执行“memcopy”,而我想“list(x)”方法无法执行相同的优化,至少在进行了许多其他样板文件之后,它才能执行要接受许多类型的构造函数所必须做的工作。但在没有深入源代码之前,这只是纯粹的猜测。 - aruisdante
@aruisdante 列表构造函数肯定首先要检查 PyList_CheckExact,但这只是指针算术和 C 级分支(最多几十个周期),所以我认为它不会是一个重要因素。 - user395760
1个回答

12

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

区别在于增加了函数调用(只是使用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 

来自dis文档:

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

(TOS - 栈顶)

CALL_FUNCTION(argc)
调用函数。 argc 的低字节表示定位参数的数量,高字节表示关键字参数的数量。在栈上,操作码首先找到关键字参数。对于每个关键字参数,其值在前面的key之上。在关键字参数下面,位置参数在栈上,最右边的参数在顶部。在参数下面,要调用的函数对象在栈上。弹出所有函数参数和函数本身,然后推入返回值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接