Python:为什么列表推导比for循环慢?

8

基本上这些函数是相同的 - 除了列表推导式使用sum而不是x=0; x+=,因为后者不被支持。为什么列表推导式编译成的代码会慢40%?

#list comprehension
def movingAverage(samples, n=3): 
    return [float(sum(samples[i-j] for j in range(n)))/n for i in range(n-1, len(samples))]

#regular
def moving_average(samples, n=3):
    l =[]
    for i in range(n-1, len(samples)):
        x= 0
        for j in range(n): 
            x+= samples[i-j]
        l.append((float(x)/n))
    return l

在计时样本输入时,我使用了[i*random.random() for i in range(x)]的变化。

注:该代码为Python语言。

你正在列表推导式中进行一些额外的操作,比如转换为float并除以n - Christian Tapia
我两个都有浮点数。我只是忘记在stackoverflow上添加它了。这是因为我在测试Python2时默认将除法转换为整数。 - user3467349
1个回答

16

你在列表推导式中使用了一个生成器表达式:

sum(samples[i-j] for j in range(n))

生成器表达式每次运行都需要创建一个新的框架,就像函数调用一样。这相对比较昂贵。

您根本不需要使用生成器表达式;您只需要切片 samples列表:


sum(samples[i - n + 1:i + 1])

你可以指定第二个参数,即 sum() 函数的 起始值;将其设置为 0.0 可以得到浮点数结果:

sum(samples[i - n + 1:i + 1], 0.0)

同时这些变化能够产生重大影响:

>>> from timeit import timeit
>>> import random
>>> testdata = [i*random.random() for i in range(1000)]
>>> def slow_moving_average(samples, n=3):
...     return [float(sum(samples[i-j] for j in range(n)))/n for i in range(n-1, len(samples))]
... 
>>> def fast_moving_average(samples, n=3):
...     return [sum(samples[i - n + 1:i + 1], 0.0) / n for i in range(n-1, len(samples))]
... 
>>> def verbose_moving_average(samples, n=3):
...     l =[]
...     for i in range(n-1, len(samples)):
...         x = 0.0
...         for j in range(n): 
...             x+= samples[i-j]
...         l.append(x / n)
...     return l
... 
>>> timeit('f(s)', 'from __main__ import verbose_moving_average as f, testdata as s', number=1000)
0.9375386269966839
>>> timeit('f(s)', 'from __main__ import slow_moving_average as f, testdata as s', number=1000)
1.9631599469939829
>>> timeit('f(s)', 'from __main__ import fast_moving_average as f, testdata as s', number=1000)
0.5647804250038462

谢谢你的回答,你说得对,额外的生成器框架确实存在。在切片上求和比第二个for循环更快。 - user3467349
另外我想补充的是,对于在切片上求和是否更快这一点并不明显 - 例如在Julia中,使用for循环实现的方法胜过使用切片。 - user3467349

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