在Python中什么时候应该使用生成器表达式,什么时候应该使用列表推导式?
# Generator expression
(x*2 for x in range(256))
# List comprehension
[x*2 for x in range(256)]
在Python中什么时候应该使用生成器表达式,什么时候应该使用列表推导式?
# Generator expression
(x*2 for x in range(256))
# List comprehension
[x*2 for x in range(256)]
当前回答
有时候你可以在itertools中使用tee函数,它会为同一个生成器返回多个迭代器,这些迭代器可以独立使用。
其他回答
我认为大多数答案都忽略了一点。列表推导式基本上创建一个列表并将其添加到堆栈中。在列表对象非常大的情况下,脚本进程将被杀死。在这种情况下,生成器更受欢迎,因为它的值不存储在内存中,而是存储为有状态函数。还有创造速度;列表理解比生成器理解慢
简而言之, 当obj的大小不是很大时,使用列表推导式,否则使用生成器推导式
有时候你可以在itertools中使用tee函数,它会为同一个生成器返回多个迭代器,这些迭代器可以独立使用。
遍历生成器表达式或列表推导式也会做同样的事情。但是,列表推导式将首先在内存中创建整个列表,而生成器表达式将动态地创建项,因此您可以将其用于非常大的(也是无限的!)序列。
John的回答很好(当您想要多次迭代某个内容时,列表推导式更好)。然而,同样值得注意的是,如果您想使用任何列表方法,则应该使用列表。例如,下面的代码将无法工作:
def gen():
return (something for something in get_some_stuff())
print gen()[:2] # generators don't support indexing or slicing
print [5,6] + gen() # generators can't be added to lists
基本上,如果你所做的只是迭代一次,就使用生成器表达式。如果希望存储和使用生成的结果,那么最好使用列表推导式。
由于性能是最常见的选择一个而不是另一个的原因,我的建议是不要担心,只选择一个;如果您发现您的程序运行得太慢,那么只有在这时,您才应该返回并考虑调优您的代码。
关于内置Python函数的一些注意事项:
如果需要利用任何或全部的短路行为,请使用生成器表达式。这些函数被设计为在已知答案时停止迭代,但是列表推导式必须在调用函数之前计算每个元素。
例如,如果我们有
from time import sleep
def long_calculation(value):
sleep(1) # for simulation purposes
return value == 1
然后any([long_calculation(x) for x in range(10)])大约需要10秒,因为long_calculation将为每个x调用,any(long_calculation(x) for x in range(10))只需要大约2秒,因为long_calculation只会在0和1输入时被调用。
当any和all遍历列表理解时,一旦已知答案,它们仍然会停止检查元素的真实性(只要any发现一个真结果,或者all发现一个假结果);然而,与理解所做的实际工作相比,这通常是微不足道的。
生成器表达式当然更节省内存,如果可能的话。使用非短路的min, max和sum (max的计时如图所示),列表推导会稍微快一些:
$ python -m timeit "max(_ for _ in range(1))"
500000 loops, best of 5: 476 nsec per loop
$ python -m timeit "max([_ for _ in range(1)])"
500000 loops, best of 5: 425 nsec per loop
$ python -m timeit "max(_ for _ in range(100))"
50000 loops, best of 5: 4.42 usec per loop
$ python -m timeit "max([_ for _ in range(100)])"
100000 loops, best of 5: 3.79 usec per loop
$ python -m timeit "max(_ for _ in range(10000))"
500 loops, best of 5: 468 usec per loop
$ python -m timeit "max([_ for _ in range(10000)])"
500 loops, best of 5: 442 usec per loop