为什么从生成器对象创建列表需要这么长时间?

时间:2016-07-09 18:51:19

标签: python list python-3.x generator timeit

我对何时应该在函数中使用生成器感兴趣,当我应该使用列表时,所以我使用过滤器和列表推导进行了一些测试。

Set src = ThisWorkbook.VBProject.VBComponents("Module2").CodeModule
Set dest = ActiveWorkbook.VBProject.VBComponents("Sheet2") _
.CodeModule

dest.DeleteLines 1, dest.CountOfLines
dest.InsertLines 1, src.Lines(1, src.CountOfLines)

然后我尝试了范围(100):

>>> timeit.timeit('list(filter(lambda x: x%10, range(10)))')
3.281250655069016
>>> timeit.timeit('[i for i in range(10) if i%10 != 0]')
2.6070076799951494
>>> timeit.timeit('filter(lambda x: x%10, range(10))')
0.7457015149993822   

为什么从生成器对象创建列表所需的时间比创建列表要长得多?如果我需要不止一次访问该列表,我会更好地使用列表理解而不是从生成器对象创建列表吗?

2 个答案:

答案 0 :(得分:3)

问题

有两个不同的问题
  1. 从独立过滤器调用的微小计时数据可以看出,您使用的是Python 3.x,因为过滤器返回类似于对象的生成器。所以理论上没有任何实际发生。[1]
  2. 第一个表达式调用一个lambda,一个在Python中总是很昂贵的函数调用。因此,List comprehension在调用包含列表内置的lambda的过滤器方面表现优异。[2]

答案 1 :(得分:-1)

我将首先回答您的上一个问题,是的,您应该使用全面的列表,而不是list + filter组合,因为它更加pythonic并且当您展示它时,效率更高。< / p>

至于为什么效率更高,你在lambda代码中的函数调用开销(filter)在理解列表中没有。

这是另一个向您展示的时间测试:

# First the sample with list & filter, for comparison base
>>> timeit.timeit('list(filter(lambda x: x%10, range(10)))')
10.984653161001916
# Then the quickest comprehension list
>>> timeit.timeit('[i for i in range(10) if i%10]')
6.125996000002488
# And an hybrid, comprehension list using a call to previously defined lambda
>>> timeit.timeit('[i for i in range(10) if l(i)]', setup="l=lambda x: x%10")
9.257114547002857

如您所见,大部分差异来自函数调用开销。

最后1.7个无法解释的秒可能是由于filter弹出到list,而理解列表将值直接构建到列表中