Python:为什么列表理解比for循环慢

时间:2015-01-12 15:58:15

标签: python performance list-comprehension

基本上这些是相同的功能 - 除了列表理解使用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)]

上的变体

1 个答案:

答案 0 :(得分:13)

您在列表推导中使用了生成器表达式:

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

生成器表达式需要在每次运行时创建一个新帧,就像函数调用一样。这是相对昂贵的。

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

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

您可以指定第二个参数,sum() functionstart值;将其设置为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