生成器表达式是Python中一个有意思的功能,允许我们创建惰性加载的可迭代对象。如果你的数据太大以至于会让内存爆掉,它是一个非常好的选择。

什么是生成器表达式

还记得列表解析怎么写吧,它得到的是一个可迭代对象。如果你把方括号换成圆括号,它就变成了生成器解析,得到的就是一个生成器对象。

list_comprehension = [f(i) for i in range(10)] # for some function f...

list_generator = (f(i) for i in range(10) ) # for some function f...

在生成器中,某个元素并没有真正的被创建,也就不占有内存空间,除非它被读入到内存中。所以,你不能如同操作列表那样进行索引和切片,这也是生成器和列表的重要区别,虽然它们都是可迭代的。也是因为上述原因,不能使用len()函数测量生成器的长度。

生成器的引用举例

为了说明生成器的用途,看下面的示例:

import sys

a_list = [1 for i in range(100000000) ]
a_generator = (1 for i in range(100000000) )

sys.getsizeof(a_list) 
sys.getsizeof(a_generator) 

以上列表和生成器中的元素内容都是一样的,但是生成器只有120Bytes,而列表则占据了859724472Bytes。从操作中你肯定也感受到了,生成器的载入速度快。很明显,对于某些问题而言,如果内存不足的话,用生成器替代列表是一项明智的选择。不过要提醒注意,前面提到的生成器与列表的区别,不要因为使用了生成器而报错。

作为迭代器的生成器

生成器也是迭代器,是可迭代的。在Python3中,每个生成器对象都有__next__方法,例如:

gen = (1 for _ in range(1000) )

# iterating manually

while True:
    try:
        my_value = gen.__next__()
        do_stuff_with(my_value)
    except:
        break



# iterating normally

for my_value in gen:
    do_stuff_with(my_value)

对于生成器,可以用于for循环,因为for循环能够自动处理StopIteration异常,所以当循环到最后能够自动停止。如果使用生成器对象的__next__方法或者使用next()内置函数,必须要捕获这个异常。

简要介绍生成器表达式,希望对你有用。