我在探索Python的itertools
模块时,发现了返回与((x,y) for x in A for y in B)
相同的itertools.product
函数。我发现这是一种非常巧妙的方法,可以减少复杂for-loops
中列表理解可能不足的嵌套。然而,在继续之前,我想检查一下它是如何使用其他方法执行的。以下是我进行的一些测试。使用Jupyter Notebook内置的%%timeit
来衡量性能。
案例1:香草清单理解
%%timeit -n 50 -r 5
[(x,y) for x in range(1000) if x%2==0 for y in range(1000) if y%2==1]
>>> 35.8 ms ± 1.3 ms per loop (mean ± std. dev. of 5 runs, 50 loops each)
案例2:列表理解中的itertools.product
删除了itertools
导入以避免此处显示导入时间。
%%timeit -n 50 -r 5
[(x,y) for (x,y) in itertools.product(range(1000), range(1000)) if x%2==0 and y%2==1]
>>> 62.1 ms ± 1.16 ms per loop (mean ± std. dev. of 5 runs, 50 loops each)
案例3:香草嵌套for循环
%%timeit -n 50 -r 5
lst = []
for x in range(1000):
for y in range(1000):
if x%2 == 0 and y%2 == 1:
lst.append((x,y))
>>> 72 ms ± 769 µs per loop (mean ± std. dev. of 5 runs, 50 loops each)
案例4:使用itertools.product进行循环
%%timeit -n 50 -r 5
lst = []
for x, y in itertools.product(range(1000),range(1000)):
if x%2==0 and y%2==1:
lst.append((x,y))
>>> 74.5 ms ± 2.13 ms per loop (mean ± std. dev. of 5 runs, 50 loops each)
然而,我想,这部分文档声称比普通的for
循环具有更好的性能。此外,case-2是否应该比case-1更快?在case3和case 4中,随着可迭代项的大小增加,itertools.product
的性能差异变得更差。这是怎么回事?此外,请添加一些示例,其中itertools.product
可能比listcomp或嵌套循环更好。
您正在比较不同的东西:
[(x,y) for x in range(1000) if x%2==0 for y in range(1000) if y%2==1]
与不同
[(x,y) for x in range(1000) for y in range(1000) if x%2==0 and y%2==1]
如果x%2 != 0
,则第一个循环完全跳过第二个循环,第二个则循环通过所有1000 ** 2 == 1,000,000
组合。案例2至4与这里的第二理解属于同一类别,因此它们天生较慢。