在Python中什么时候应该使用生成器表达式,什么时候应该使用列表推导式?

# Generator expression
(x*2 for x in range(256))

# List comprehension
[x*2 for x in range(256)]

当前回答

生成器表达式的好处是它使用更少的内存,因为它不会一次构建整个列表。生成器表达式最好在列表作为中介时使用,例如对结果求和,或从结果中创建字典。

例如:

sum(x*2 for x in xrange(256))

dict( (k, some_func(k)) for k in some_list_of_keys )

这样做的好处是列表不是完全生成的,因此占用的内存很少(而且应该更快)。

但是,当期望的最终产品是一个列表时,应该使用列表推导式。使用生成器表达式不会节省任何内存,因为您需要生成的列表。您还可以使用任何列表函数,如sorted或reversed。

例如:

reversed( [x*2 for x in xrange(256)] )

其他回答

当结果需要多次迭代时,或者在速度非常重要的情况下,使用列表推导式。在范围较大或无穷大的地方使用生成器表达式。

有关更多信息,请参阅生成器表达式和列表推导式。

Python 3.7:

列表推导更快。

生成器的内存效率更高。

正如其他人所说,如果你想要扩展无限的数据,你最终还是需要一个生成器。对于相对静态的、需要快速处理的中小型工作,最好是对清单进行理解。

我正在使用Hadoop Mincemeat模块。我认为这是一个值得注意的好例子:

import mincemeat

def mapfn(k,v):
    for w in v:
        yield 'sum',w
        #yield 'count',1


def reducefn(k,v): 
    r1=sum(v)
    r2=len(v)
    print r2
    m=r1/r2
    std=0
    for i in range(r2):
       std+=pow(abs(v[i]-m),2)  
    res=pow((std/r2),0.5)
    return r1,r2,res

在这里,生成器从一个文本文件(最大15GB)中获取数字,并使用Hadoop的map-reduce对这些数字应用简单的数学运算。如果我没有使用yield函数,而是使用一个列表理解,那么计算总和和平均值将花费更长的时间(更不用说空间复杂性了)。

Hadoop是一个很好的例子,可以使用生成器的所有优点。

对于函数式编程,我们希望使用尽可能少的索引。因此,如果我们想在获取元素的第一个切片后继续使用元素,islice()是一个更好的选择,因为迭代器状态会被保存。

from itertools import islice

def slice_and_continue(sequence):
    ret = []
    seq_i = iter(sequence) #create an iterator from the list

    seq_slice = islice(seq_i,3) #take first 3 elements and print
    for x in seq_slice: print(x),

    for x in seq_i: print(x**2), #square the rest of the numbers

slice_and_continue([1,2,3,4,5])

输出:1 2 3 16 25

有时候你可以在itertools中使用tee函数,它会为同一个生成器返回多个迭代器,这些迭代器可以独立使用。