1. 生成器:
(1)在 Python 中, 一边循环一边计算的机制,称为生成器(Generator);
(2)生成器是Python中的一个对象,对这个对象进行操作,可以依次生产出按生成器内部运算产生的数据;
(3)生成器可以通过生成器表达式和生成器函数获取到;
2. 什么是生成器函数:
生成器函数指的是函数体中包含yield关键字的函数(yield就是专门给生成器用的return)。一般来说,生成器函数和常规函数一样,事实上也是用常规的def语句编写的。然而,当创建时,它们被特殊地编译成一个支持迭代协议的对象。并且在调用的时候它们不会返回一个结果,它们返回一个可以出现在任何迭代上下文中的结果生成器。
3. 状态挂起
生成器函数能够自动挂起并在生成值的时刻恢复之前的状态并继续函数的执行。由于生成器函数在挂起时保存的状态包含它们的代码位置和整个局部作用域。yield语句会挂起该函数并向调用者传加一个值,但同时也保留了足够的状态使函数能从它离开的地方继续。
与迭代协议集成,迭代器对象定义一个__next__方法(在2.X中的next),它要么返回迭代中的下一项,要么引发一个特殊的StopIteration异常来终止迭代。
为了支持这一协议,函数必须包含一条 yield语句,该函数将被特别编译为生成器:它们不再是普通函数,而是作为特定的迭代协议方法来返回对象的函数。当调用时,它们返回一个生成器对象,该对象支持用一个自动创建的名为__next__的方法接口,来开始或恢复执行。也就是说,被返回的生成器对象有一个__next__方法,该方法可以开始这个函数,或者从它上次yield值后的地方恢复,并且在得到一系列值的最后一个时,引发一个StopIteration异常。
4. 成生器函数的应用:
(1)生成器函数是一种“穷人的”多线程机制:它们通过把操作拆分到每一次的yield之间,从而将一个函数的执行交错地插入它的调用者的工作中。
(2)生成器的send()方法:send()方法相当于一种调用者与生成器之间进行通信的方式,从而能得到影响生成器的操作。值可以通过调用 G.send(value)发送给一个生成器G,手动结束yield延迟,恢复生成器代码的执行,并且生成器中的yield表达式返回了发送给send函数的值。
(3)next(G) ,要么返回生成器G的下一项,要么引发一个StopIteration异常,next(G)等同于G.__next__().
def gen():
for i in range(8):
x = yield i # 把 i yield 出去,然后还没赋值就挂起了,等回来时再进行赋值
print(x)
G = gen()
print(G) # <generator object gen at 0x000001E5FFAB1F48>
X0 = next(G) # next() 要么返回迭代器的下一项,要么引发一个特殊的StopIteration异常
print("Out of func X0=%d" % X0 if isinstance(X0, int) else "Out of func X0=None")
"""
Out of func X0=0
None 理解:生成器已经把值返回给了调用者,然后next()又催生成器进行下一个循环,但此时还没计算出下一个值,就print(x),所以print出来是None(这个None是print(x)打印的)
"""
X1 = next(G)
print("Out of func X1=%d" % X1 if isinstance(X1, int) else "Out of func X1=None")
"""
Out of func X1=1
None
"""
X2 = next(G)
print("Out of func X2=%d" % X2 if isinstance(X2, int) else "Out of func X2=None")
"""
Out of func X2=2
"""
X3 = G.send(77) # 生送一个值给生成器G,并且生成器中的yield表达式返回了发送给send()的值
print("Out of func X3=%d" % X3 if isinstance(X3, int) else "Out of func X3=None")
"""
77 (这里是 print(x) 打印的,send(77)后,马上恢复赋值给了x,然后打印出了 77)
Out of func X3=3
None
"""
X4 = next(G)
print("Out of func X4=%d" % X4 if isinstance(X4, int) else "Out of func X4=None")
"""
Out of func X4=4
None
"""
X5 = G.__next__() # 跟 next(G)一样
print("Out of func X5=%d" % X5 if isinstance(X5, int) else "Out of func X5=None")
"""
Out of func X5=5
"""
5. 生成器表达式
从语法上来讲,生成器表达式就像一般的列表推导一样,而且也支持所有列表推导的语法(包括if过滤器和循环嵌套),但它们是包括在圆括号中而不是方括号中的(跟元组一样,它们的圆括号通常是可选的)。
# 列表推导式 build a list
[x**2 for x in range(4)]
# [0, 1, 4, 9]
# 生成器表达式 make an iterable
(x**2 for x in range(4))
# <generator object <genexpr> at 0x00000000029A8288>