[英]generator vs list comprehension
in
对生成器表达式的使用将使用__iter__()
方法并迭代该表达式直到找到匹配项,这使其在一般情况下比列表理解更有效,后者首先会生成整个列表,然后再扫描结果以查找匹配项。
您的特定示例的替代方法是使用any()
,以使测试更加明确。 我觉得这更具可读性:
any(x[0] == 3 for x in l)
你必须考虑到, in
做前进的发电机; 如果还需要在其他地方使用生成器,则不能使用此方法。
至于您的特定计时测试; 您的“短期”测试存在致命缺陷。 izip()
生成器的第一个迭代将完全耗尽,从而使其他9999个迭代针对空生成器进行测试。 您正在测试在其中创建一个空列表和一个空生成器之间的差异,从而扩大了创建成本的差异。
此外,您应该使用timeit
模块运行测试,确保测试可重复 。 这意味着您还必须在每次迭代时都创建一个新的izip()
对象。 现在,对比度要大得多 :
>>> # Python 2, 'short'
...
>>> timeit.timeit("l = izip(xrange(10**2), xrange(10**2)); 3 not in (x[0] for x in l)", 'from itertools import izip', number=100000)
0.27606701850891113
>>> timeit.timeit("l = izip(xrange(10**2), xrange(10**2)); 3 not in [x[0] for x in l]", 'from itertools import izip', number=100000)
1.7422130107879639
>>> # Python 2, 'long'
...
>>> timeit.timeit("l = izip(xrange(10**3), xrange(10**3)); 3 not in (x[0] for x in l)", 'from itertools import izip', number=100000)
0.3002200126647949
>>> timeit.timeit("l = izip(xrange(10**3), xrange(10**3)); 3 not in [x[0] for x in l]", 'from itertools import izip', number=100000)
15.624258995056152
在Python 3上:
>>> # Python 3, 'short'
...
>>> timeit.timeit("l = zip(range(10**2), range(10**2)); 3 not in (x[0] for x in l)", number=100000)
0.2624585109297186
>>> timeit.timeit("l = zip(range(10**2), range(10**2)); 3 not in [x[0] for x in l]", number=100000)
1.5555254180217162
>>> # Python 3, 'long'
...
>>> timeit.timeit("l = zip(range(10**3), range(10**3)); 3 not in (x[0] for x in l)", number=100000)
0.27222433499991894
>>> timeit.timeit("l = zip(range(10**3), range(10**3)); 3 not in [x[0] for x in l]", number=100000)
15.76974998600781
在所有情况下,生成器变体都快得多; 您必须将“简短”版本缩短为仅8个元组,列表理解才能开始获胜:
>>> timeit.timeit("n = 8; l = izip(xrange(n), xrange(n)); 3 not in (x[0] for x in l)", 'from itertools import izip', number=100000)
0.2870941162109375
>>> timeit.timeit("n = 8; l = izip(xrange(n), xrange(n)); 3 not in [x[0] for x in l]", 'from itertools import izip', number=100000)
0.28503894805908203
在Python 3上,生成器表达式和列表推导的实现更加接近了,在列表推导胜出之前,您必须降低4个项目:
>>> timeit.timeit("n = 4; l = zip(range(n), range(8)); 3 not in (x[0] for x in l)", number=100000)
0.284480107948184
>>> timeit.timeit("n = 4; l = zip(range(n), range(8)); 3 not in [x[0] for x in l]", number=100000)
0.23570425796788186
创建生成器比创建列表要慢,因此您必须考虑变量:创建对象的时间和测试表达式的时间。 因此,要回答您的问题,如果“更好”表示“更快”:取决于n
。
创建生成器表达式会产生很多开销,但是最终您不需要分配大量内存来弥补它。
小列表理解速度更快,因为它们没有这些开销。
通常情况下,小案例足够接近,因此在这种情况下,最好选择生成器表达式
在Web服务器上保留可能同时存在100或1000个连接的内存尤为重要。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.