生成器
一、什么是生成器
生成器是一种用普通的函数语法定义的迭代器。
什么是Python式的生成器?从语法上讲,生成器是一个带yield语句的函数。
一个函数或者子程序只返回一次,但一个生成器能暂停执行并返回一个中间的结果——那就是yield语句的功能,返回一个值给调用者并暂停执行。
当生成器的next()方法被调用的时候,他会准确的从离开的地方继续。
生成器不会把结果保存在一个系列中,而是保存生成器的状态,在每次进行迭代时返回一个值,直到遇到StopIteration异常结束。
生成器表达式能做的事情列表解析基本都能处理,只不过需要处理的序列比较大时,列表解析比较费内存。
生成器函数:在函数中如果出现了yield关键字,那么该函数就不再时普通函数,而是生成器函数。
但是生成器函数可以产生一个无线的序列,这样列表根本没有办法进行处理。
yield的作用就是把一个函数变成一个generator,带有yield的函数不再是一个普通函数。python解释器会将其视为一个generator。
如果要打印一列数,用函数这样写:
def fibs(num): result = [0,1] for i in range(num-2): result.append(result[-2]+result[-1]) return result print(fibs(10)) 执行结果: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
函数只能返回一次,所以必须返回一个阵列。如果换成生成器,就可以一次返回一个值,不断返回多次。如果使用生成,它就会不断地调用生成器对象的next()方法。
二、创建一个简单的生成器
#使用生成器打印表中所有的值。 def flatten(nested): for sublist in nested: for element in sublist: yield element nested = [[1,2,3],[4,5],(6,7)] for num in flatten(nested): print(num) #执行结果 1 2 3 4 5 6 7
如果用列表解析也能实现:
for m in nested: for n in m: print(n)
如果是多层,该如何实现了?——递归生成器
三、递归生成器
上面所讲述的生成器可以处理多层嵌套。如何处理任意层嵌套了?
def flatten(nested): try: for sublist in nested: for element in flatten(sublist): yield element except TypeError: yield nested nested = [[1,2],[[11],3,4,(8,9,10),5]] for i in flatten(nested): print(i)
当flatten被调用时,有两种可能性:基本情况和需要递归的情况。在基本的情况中,函数被告知展开一个元素(比如一个数字),这种情况下,for循环会引发一个TypeError异常,因为试图对一个数字进行迭代,生成器会产生一个元素。如果展开的是一个列表(或者其它可迭代对象),那么就要进行特殊处理。程序必须便利所有的子列表(可能不是列表),并对调用flatten。然后使用另一个for循环来产生被展开的子列表中的所有元素。
def flatten(nested): try: try:nested + '' except TypeError:pass else: raise TypeError for sublist in nested: for element in flatten(sublist): yield element except TypeError: yield nested print(list(flatten(['foo',['bar',['baz','1','2']]])))
四、通用生成器
生成器是一个包含yield关键字的函数。当它被调用时,在函数体中的代码不会被执行,而是返回一个迭代器。
每次请求一个值,就会执行生成器中的代码,直到遇到一个yield或者return语句,yield语句意味着应该生成一个值,return语句意味着生成器要停止执行。
生成器是由两部分组成:生成器的函数和生成器的迭代器。生成器的函数是用def语句定义的,包含yield的部分,生成器的迭代器是这个函数返回的部分。