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

Python:为什么列表理解比for循环慢,python,performance,list-comprehension,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):

本质上,这些函数是相同的-除了列表理解使用
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

为了给样本输入计时,我使用了范围(x)内I的变量[I*random.random()

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

sum(samples[i-j] for j in range(n))
生成器表达式要求在每次运行一个框架时创建一个新框架,就像函数调用一样。这是相对昂贵的

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

sum(samples[i - n + 1:i + 1])
您可以为指定第二个参数,即
start
值;将其设置为
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

您在列表理解中进行了一些额外的操作,例如转换为
float
并除以
n
。两者中都有float。我只是忘了将它添加到stackoverflow中。这是因为我在Python2中进行测试,Python2在除法中默认为int。谢谢你的回答,关于额外的生成器框架,你是对的。一个切片上的求和比一秒for循环快。另外,我想补充的是,一个切片上的求和速度并不明显——例如,在Julia中,for循环的实现比切片的执行速度快。