yield
带有 yield 的函数在 Python 中被称之为 generator(生成器),生成器(generator)能够迭代的关键是它有一个next()方法,工作原理就是通过重复调用next()方法,直到捕获一个异常。
生成器与迭代器会在另一篇文章介绍
yield 是一个类似 return的关键字,迭代一次遇到yield时就返回yield后面的值。重点是:下一次迭代时,从上一次迭代遇到的yield后面的代码开始执行。
简要理解:yield就是 return 返回一个值,并且记住这个返回的位置,下次迭代就从这个位置后开始。
首先先举例了解下yield的用法
def myyield(): print ( ' start program ' ) while True: res = yield ' yes ' print ( ' resprint: ' ,res) test =myyield()
运行这段代码会怎么样呢?
C:\Users\11573\AppData\Local\Programs\Python\Python36\python.exe D:/pythonwork/socket/
test.py
Process finished with exit code 0
奇怪,竟然什么都没有打印,按理说至少会打印一个 start program 才对,但是运行过后什么都没有,这是为什么呢?
next()
程序开始执行以后,因为myyield函数中有yield关键字,所以myyield函数并不会真的执行,而是先得到一个生成器test(相当于一个对象),直到我们调用next方法,myyield函数正式开始执行,先执行myyield函数中的print方法,然后进入while循环
我们修改下代码
def myyield(): print ( ' starting program ' ) while True: res = yield ' yes ' print ( ' resprint: ' ,res) test = myyield() print (next(test))
可以看到结果如下:
C:\Users\11573\AppData\Local\Programs\Python\Python36\python.exe D:/pythonwork/socket/
test.py
starting program
yes
有两行输出 但是我们发现并没有执行
print('resprint:'
,res)
这行代码,这是因为程序遇到yield关键字,然后把yield想像成return,return了一个yes之后,程序停止,并没有执行赋值给res操作,此时next(g)语句执行完成,所以输出的前两行
那么我们再修改下代码:
def myyield(): print ( ' starting program ' ) while True: res = yield ' yes ' print ( ' resprint: ' ,res) test = myyield() print (next(test)) print ( ' // ' *20 ) print (next(test))
可以看到输出如下:
C:\Users\11573\AppData\Local\Programs\Python\Python36\python.exe D:/pythonwork/socket/ test.py starting program yes //////////////////////////////////////// resprint: None yes
除了我们用作标记的 ‘////////////////////////////////////////‘ 外 多了两行输入
我们来看下这两行输出分别来自什么语句
首先输出resprint: None 这是因为上次程序中断在yield语句处 这次执行则直接从上次断点继续执行,而上次直接返回值,所以赋值为None 因此第一行输出resprint: None
第二行输出 yes 这是因为程序在while True循环中再次运行到了yield,因此又停止运行
因此通过这个简单的程序我们可以大概知道yield的用法了,带yield的函数是一个生成器,而不是一个函数了,这个生成器有一个函数就是next函数,next就相当于“下一步”生成哪个数,这一次的next开始的地方是接着上一次的next停止的地方继续执行。
send()
yield还有一个send()函数,那么send函数的作用是什么呢?我们可以举例子来看一下send()的作用
我们在上面代码的基础上增加几行代码:
def myyield(): print ( ' starting program ' ) while True: res = yield ' yes ' print ( ' resprint: ' ,res) test = myyield() print (next(test)) print ( ' // ' *20 ) print (next(test)) print ( ' // ' *20 ) print (test.send( ' sending yes ' ))
看下输出:
C:\Users\11573\AppData\Local\Programs\Python\Python36\python.exe D:/pythonwork/socket/ test.py starting program yes //////////////////////////////////////// resprint: None yes //////////////////////////////////////// resprint: sending yes yes
奇怪,之前的resprint都是None,这次却有了赋值,
这是因为,send是发送一个参数给res的,在next函数return的时候,并没有把 'yes' 赋值给res,下次执行的时候只好继续执行赋值操作,只好赋值为None了,而如果用send的话,开始执行的时候,先接着上
一次(return yes之后)执行,先把 'sending yes' 赋值给了res,然后执行next的作用,遇见下一回的yield,return出结果后结束。send方法中包含next()方法,所以程序会继续向下运行执行print方法,然后再次
进入while循环程序执行再次遇到yield关键字,yield会返回后面的值后,程序再次暂停,直到再次调用next方法或send方法。