Python: 为什么列表理解比 for 循环慢
Python: Why is list comprehension slower than for loop
本质上这些是相同的功能 - 除了列表理解使用 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)]
的变体
您在列表理解中使用了生成器表达式:
sum(samples[i-j] for j in range(n))
每次 运行 生成器表达式都需要创建一个新框架,就像函数调用一样。这个比较贵。
您根本不需要使用生成器表达式;您只需要 slice samples
列表:
sum(samples[i - n + 1:i + 1])
您可以指定第二个参数,sum()
function 的 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
本质上这些是相同的功能 - 除了列表理解使用 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)]
您在列表理解中使用了生成器表达式:
sum(samples[i-j] for j in range(n))
每次 运行 生成器表达式都需要创建一个新框架,就像函数调用一样。这个比较贵。
您根本不需要使用生成器表达式;您只需要 slice samples
列表:
sum(samples[i - n + 1:i + 1])
您可以指定第二个参数,sum()
function 的 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