我尝试了两种实现,一种使用生成器,一种不使用生成器。我在 2.7 中对其进行了测试,因此range
返回一个列表而不是迭代器。
这是实现
使用生成器
def foo1():
data = ((a,b) for a in (i*i for i in xrange(1,101) if i%2) for b in [1,2,3,4,5] if a+b > 40)
return list(data)
没有发电机
def foo2():
result=[]
for i in range(1,101):
if i%2:
i=i*i
for j in [1,2,3,4,5]:
if i+j > 40:
result+=[(i,j)]
return result
混合两者以免附加列表
def foo3():
data=[(a,b) for a in (i*i for i in range(1,101)) for b in [1,2,3,4,5] if a+b > 40]
return data
创建临时列表
def foo4():
data=[(a,b) for a in [i*i for i in range(1,101)] for b in [1,2,3,4,5] if a+b > 40]
return data
这是我的结果
>>> t1=timeit.Timer("foo1()","from __main__ import foo1")
>>> t2=timeit.Timer("foo2()","from __main__ import foo2")
>>> t3=timeit.Timer("foo3()","from __main__ import foo3")
>>> t4=timeit.Timer("foo4()","from __main__ import foo4")
>>> print "%.2f usec/pass" % (1000000 * t1.timeit(number=10000)/10000)
100.95 usec/pass
>>> print "%.2f usec/pass" % (1000000 * t2.timeit(number=10000)/10000)
158.90 usec/pass
>>> print "%.2f usec/pass" % (1000000 * t3.timeit(number=10000)/10000)
130.02 usec/pass
>>> print "%.2f usec/pass" % (1000000 * t4.timeit(number=10000)/10000)
133.68 usec/pass
>>>
结论:
生成器表达式功能强大,您可以对其进行更大程度的优化。正如您在示例中看到的那样foo2
,这是最慢的,它很难附加一个导致性能下降的列表。foo3
并且foo4
时间几乎相同,因此创建临时列表似乎不是瓶颈,因为它在整个迭代中只创建了一次。如果没有生成器,您很快就会遇到一些性能问题,例如附加列表或创建临时列表。因此,懒惰的评估出现在这些性能瓶颈上。