日期:20171022
yield,中文意思是屈服,投降,退让。
我的理解是主动退让,为什么要加主动呢?
其实yield,就是操作系统中的“挂起”。而挂起是线程自己主动挂起的,并非其他线程或者系统强迫它。
那么yield,可以理解为主动挂起。
yield from
虽然开头说了一下yield,但是今天的主角是yield from。
先来看一下代码
代码,
#
#--test_yield_from.py
def func2():
print("func 2 called")
yield 2
print("func 2 finished")
return "go back"
def func1():
print("func 1 called")
a=yield from func2()
print(a)
print("func 1 finished")
return "OK"
g=func1() ##创建func1生成器
x=next(g) ##启动生成器g
print(x)
next(g) ##再次运行生成器g
运行结果,
[penx@vBox_Arch python]$ python test_yield_from.py
func 1 called
func 2 called
2
func 2 finished
go back
func 1 finished
Traceback (most recent call last):
File "test_yield.py", line 20, in <module>
next(g)
StopIteration: OK
[penx@vBox_Arch python]$
结果分析,
直接来分析代码运行过程吧!
1、main函数,先创建func1生成器g
2、next(g),启动g,进入函数func1
3、print(“func 1 called”)
4、yield from func2(),进入函数func2
5、print(“func 2 called”)
6、yield 2,生成器g挂起,回到main函数
7、把得到的2赋给x,print(x)
8、next(g),再次运行生成器g。这里并不是回到func1,而是回到func2的print(“func 2 finished”)
9、print(“func 2 finished”)
10、return “go back”,回到func1
11、把返回的”go back”赋给a,print(a)
12、print(“func 2 finished”)
13、return “OK”,产生StopIteration,回到main函数
14、结束
关键在第6步和第8步,
第6步,yield返回时,并不通过func1,而是直接返回到main函数。
而第8步,main函数再次next(g)时,回到的是第6步func2中yield 2的下一指令。
序列图
(有机会再画)
程序图
下面是我做了一个小小的gif加深自己对yield from运行过程。
感谢gif.net免费提供各种制作gif的工具,而且比其他收费的好用多了。
注:图中有虚线和双箭头,和传统上的程序流程图不同,但是作为一个iter, 不能墨守陈规,对不?
总结
最后,我们应更新一下对生成器的认识。
在多数教程中,说yield时,都是说有yield的函数,python解析为生成器。这句话在单一含有yield函数时,是没错的。
但没有yield的函数就不能作为生成器吗?并不是。
这里是我自己的理解,
1、含有yield和yield from的函数,叫生成器函数。而在调用生成器函数时,才产生一个生成器。
2、yield from 要接一个生成器函数
3、生成器,并不仅仅为单一个含有yield的函数,而是以yield from连接,以yield返回的函数链。
更深入的说,
一个生成器类似一个线程,他可以用yield挂起,next(),send()等等唤醒。