Python:yield關鍵字以及next、send函式的作用

NO IMAGE

yield與生成器

def func(n):
for i in range(0, n):
print('func: ', i)
# yield i
f = func(10)

程式執行結果:

func:  0
func:  1
func:  2
func:  3
func:  4
func:  5
func:  6
func:  7
func:  8
func:  9

當我們把註釋去掉後:

def func(n):
for i in range(0, n):
print('func: ', i)
yield i
f = func(10)

程式沒有任何輸出。

輸出此函式:
print(func(10))

得到

<generator object func at 0x0000004B57353A98>
我們得出以下結論:
1、帶有yield關鍵字的函式自動變成生成器
2、生成器被呼叫時不會立即執行
那麼,怎麼獲得生成器的生成的值呢
使用next函式:
import time
def func(n):
for i in range(0, n):
print('func: ', i)
yield i
f = func(10)
while True:
print(next(f))
time.sleep(1)

程式輸出:

func:  0
0
func:  1
1
func:  2
2
func:  3
3
func:  4
4
func:  5
5
func:  6
6
func:  7
7
func:  8
8
func:  9
9
Traceback (most recent call last):
File "C:/Users/mingC/PycharmProjects/pro_test/Demo/Demo4.py", line 9, in <module>
print(next(f))
StopIteration

結論:

1、對於生成器,當呼叫函式next(generator)時,將獲得生成器yield後面表示式的值;
2、當生成器已經執行完畢時,再次呼叫next函式,生成器會丟擲StopIteration異常
擴充套件:
1、當生成器內部執行到return語句時,自動丟擲StopIteration異常,return的值將作為異常的解釋
2、外部可以通過generator.close()函式手動關閉生成器,此後呼叫next或者send方法將丟擲異常

next與send函式

next函式與send函式很相似,都能獲得生成器的下一個yield後面表示式的值,不同的是send函式可以向生成器傳參
import time
def func(n):
for i in range(0, n):
arg = yield i
print('func:', arg)
f = func(10)
while True:
print('main:', next(f))
print('main:', f.send(100))
time.sleep(1)

輸出結果:

main: 0
func: 100
main: 1
func: None
main: 2
func: 100
main: 3
func: None
main: 4
func: 100
main: 5
func: None
main: 6
func: 100
main: 7
func: None
main: 8
func: 100
main: 9
Traceback (most recent call last):
func: None
File "C:/Users/mingC/PycharmProjects/pro_test/Demo/Demo4.py", line 9, in <module>
print('main:', next(f))
StopIteration

程式首先呼叫next函式,使得生成器執行到第4行的時候,把i的值0作為next函式的返回值返回,程式輸出main:0,然後生成器暫停。程式往下呼叫send(100)函式,

生成器從第四行繼續執行,send函式的引數100作為yield的返回值,並賦值給arg,然後得到func:100的輸出。
簡單的說,send函式使得yield關鍵字擁有了返回值返回給它的左值。

常見錯誤

import time
def func(n):
for i in range(0, n):
arg = yield i
print('func:', arg)
f = func(10)
while True:
print('main:', f.send(100))
time.sleep(1)

輸出:

Traceback (most recent call last):
File "C:/Users/mingC/PycharmProjects/pro_test/Demo/Demo4.py", line 9, in <module>
print('main:', f.send(100))
TypeError: can't send non-None value to a just-started generator

錯誤說明顯示:不能將一個非None的值傳給初始的生成器

從上面的測試,我們知道,當呼叫send函式前,生成器內部應該執行到yield所在的語句並暫停。而在這次的測試中,我們從一開始就呼叫send並傳了一個引數,
程式報錯誤。
因此,在呼叫帶非空引數的send函式之前,我們應該使用next(generator)或者send(None)使得生成器執行到yield語句並暫停。
import time
def func(n):
for i in range(0, n):
arg = yield i
print('func:', arg)
f = func(5)
print('main:', f.send(None))
while True:
print('main:', f.send(100))
time.sleep(1)

輸出結果:

main: 0
func: 100
main: 1
func: 100
main: 2
func: 100
main: 3
func: 100
main: 4
func: 100
Traceback (most recent call last):
File "C:/Users/mingC/PycharmProjects/pro_test/Demo/Demo4.py", line 10, in <module>
print('main:', f.send(100))
StopIteration

關於yield from

yield from 用於生成器的巢狀。詳細解釋可以看這篇博文:http://blog.theerrorlog.com/yield-from-in-python-3.html
奮鬥這是我寫的第一篇博文,雖然知識點不多,但是也是對自己學習的一個小總結,希望以後能夠堅持將自己程式設計路上的所思所想寫到這裡,感謝認真觀看這篇博文的朋友們。