Python的生成器(generator)是一种迭代器,可以通过next函数访问,也可以在for...in...循环中遍历。生成器有自己的特殊的语法,有点像推导式(List Comprehension),也可以在自定义的函数使用yield关键词。

生成器的出现,跟迭代器一样,也是为了在内存使用方面更友好。 有时候,序列或集合内的元素的个数非常巨大,如果全都制造出来并放入内存,对计算机的压力是非常大的。假设我们需要获取一个10**20次方如此巨大的数据序列,把每一个数都生成出来,并放在一个内存的列表内,这是很粗暴的方式,有如此大的内存么?如果元素可以按照某种算法推算出来,需要计算到哪里,就计算到哪里,就可以在循环的过程中不断推算出后续的元素,而不必创建完整的元素集合,从而节省大量的空间。

用括号(())创建生成器

>>> g = (x for x in range(3))
>>> g
>>> next(g)
0
>>> next(g)
1
>>> next(g)
2
>>> next(g)
Traceback (most recent call last):
File "", line 1, in 
StopIteration
>>> for i in g:
... print(i)
...
>>>

生成器通过与推导式(List Comprehension)相同的语法(放在括号内)被创造出来,然后通过next函数访问其元素,知道出现StopIteration异常。此时,生成器中的元素已经被清除。

用yield关键词自定义生成器函数

这是一个更加灵活的创建Python生成器的方式,我先给出示例代码:

>>> def testg():
... for i in range(3):
... yield i
... return
...
>>> for j in testg():
... print(j)
...
0
1
2

testg函数就是一个生成器函数,每当代码执行到yield语句的时候,就像return一样,testg返回一个值,并且记住了这个位置,下一次再进入testg函数的时候,从上次yield返回的位置开始继续执行,直到下一个yield,或者最后的真正的return。

testg函数被放在了for...in...语句中调用,确保了每一次testg yield一个值,循环体就开始执行,下一次循环之前,会再次进入testg函数,等待下一个yield。这就是自定义的生成器函数。可以看出,testg函数将一个序列的每一个值,一次一个的返回给上层代码,但是并没有讲每个值都保存下来,这样就起到了节省内存的作用。

yield语句还可以返回复杂的tuple,这正是generator更加灵活的地方。

>>> def g2():
... for i in range(3):
... yield i,i**2,i**3
... return
...
>>> for a,b,c in g2():
... print(a,b,c)
...
0 0 0
1 1 1
2 4 8
>>>
>>> k = g2() # another use case
>>> next(k)
(0, 0, 0)
>>> next(k)
(1, 1, 1)
>>> next(k)
(2, 4, 8)
>>> next(k)
Traceback (most recent call last):
File "", line 1, in 
StopIteration

yield一下子吐出来3个值,全部在外层的for循环中被处理。生成器还可以直接赋值给一个变量,用next函来访问,效果跟在for循环中是一样的。

以上就是对Python生成器的介绍,希望对你的代码有帮助。

-- EOF --