Python 3.4中的切片速度是否真的慢?

uh *_*per 11 python performance python-2.7 python-3.4

这个问题和我的回答让我想到了Python 2.7和Python 3.4之间的这种特殊区别.以简单的示例代码为例:

import timeit
import dis

c = 1000000
r = range(c)
def slow():
    for pos in range(c):
        r[pos:pos+3]

dis.dis(slow)

time = timeit.Timer(lambda: slow()).timeit(number=1)
print('%3.3f' % time)
Run Code Online (Sandbox Code Playgroud)

在Python 2.7中,我始终如一地获得0.165~Python 3.4 0.554~.反汇编之间唯一重要的区别是Python 2.7发出SLICE+3字节代码,而Python 3.4 BUILD_SLICE随后发出BINARY_SUBSCR.请注意,我已经从其他问题中消除了潜在减速的候选者,即字符串和xrangePython 3.4中不存在的事实(range无论如何,它应该与后者的类相似).

使用itertools' islice两者之间几乎完全相同的时间,所以我高度怀疑这是切片,这是造成差异的原因.

为什么会发生这种情况,是否存在指向行为变化的权威来源的链接?

编辑:为了回答答案,我已经将range对象包裹起来list,这确实给出了明显的加速.然而,当我增加迭代次数时,timeit我注意到时序差异变得越来越大.作为一个完整性检查,我替换切片与None看看会发生什么.

500次迭代timeit.

c = 1000000
r = list(range(c))
def slow():
    for pos in r:
        None
Run Code Online (Sandbox Code Playgroud)

收益率10.688和收益率9.915.分别用for pos in islice(r, 0, c, 3)yield 7.626和for替换for循环6.270.分别替换Noner[pos]屈服20~28~.r[pos:pos+3]收益率67.531和收益率106.784.

如您所见,时间差异很大.同样,我仍然相信这个问题与此没有直接关系range.

use*_*ica 10

在Python 2.7上,您将遍历列表并切片列表.在Python 3.4上,你将迭代range切片arange.

当我在两个Python版本上运行带有列表的测试时:

from __future__ import print_function
import timeit
print(timeit.timeit('x[5:8]', setup='x = list(range(10))'))
Run Code Online (Sandbox Code Playgroud)

我得到关于Python 2.70.243554830551秒0.29082867689430714秒关于Python 3.4,一个更小的差异.


消除range对象后看到的性能差异要小得多.它主要来自两个因素:在Python 3上添加速度稍慢,而Python 3需要__getitem__使用切片对象进行切片,而Python 2则需要__getslice__.

我无法复制你看到的时间差异r[pos]; 你可能在这个测试中遇到了一些混淆因素.