Python生成器(send,close,throw)方法詳解

Python生成器》一節中,詳細介紹瞭如何創建一個生成器,以及生成器的基礎用法。本節將在其基礎上,繼續講解和生成器有關的一些方法。

Python生成器send()方法

我們知道,通過調用 next() 或者 __next__() 方法,可以實現從外界控制生成器的執行。除此之外,通過 send() 方法,還可以向生成器中傳值。

值得一提的是,send() 方法可帶一個參數,也可以不帶任何參數(用 None 表示)。其中,當使用不帶參數的 send() 方法時,它和 next() 函數的功能完全相同。例如:


 
  1. def intNum():
  2. print("開始執行")
  3. for i in range(5):
  4. yield i
  5. print("繼續執行")
  6. num = intNum()
  7. print(num.send(None))
  8. print(num.send(None))

程序執行結果爲:

開始執行
0
繼續執行
1

注意,雖然 send(None) 的功能是 next() 完全相同,但更推薦使用 next(),不推薦使用 send(None)。

這裏重點講解一些帶參數的 send(value) 的用法,其具備 next() 函數的部分功能,即將暫停在 yield 語句出的程序繼續執行,但與此同時,該函數還會將 value 值作爲 yield 語句返回值賦值給接收者。

注意,帶參數的 send(value) 無法啓動執行生成器函數。也就是說,程序中第一次使用生成器調用 next() 或者 send() 函數時,不能使用帶參數的 send() 函數。

舉個例子:


 
  1. def foo():
  2. bar_a = yield "hello"
  3. bar_b = yield bar_a
  4. yield bar_b
  5.  
  6. f = foo()
  7. print(f.send(None))
  8. print(f.send("C語言中文網"))
  9. print(f.send("http://c.biancheng.net"))

分析一下此程序的執行流程:
1) 首先,構建生成器函數,並利用器創建生成器(對象)f 。

2) 使用生成器 f 調用無參的 send() 函數,其功能和 next() 函數完全相同,因此開始執行生成器函數,即執行到第一個 yield "hello" 語句,該語句會返回 "hello" 字符串,然後程序停止到此處(注意,此時還未執行對 bar_a 的賦值操作)。

3) 下面開始使用生成器 f 調用有參的 send() 函數,首先它會將暫停的程序開啓,同時還會將其參數“C語言中文網”賦值給當前 yield 語句的接收者,也就是 bar_a 變量。程序一直執行完 yield bar_a 再次暫停,因此會輸出“C語言中文網”。

4) 最後依舊是調用有參的 send() 函數,同樣它會啓動餐廳的程序,同時將參數“http://c.biancheng.net”傳給 bar_b,然後執行完 yield bar_b 後(輸出 http://c.biancheng.net),程序執行再次暫停。

因此,該程序的執行結果爲:

hello
C語言中文網
http://c.biancheng.net

Python生成器close()方法

當程序在生成器函數中遇到 yield 語句暫停運行時,此時如果調用 close() 方法,會阻止生成器函數繼續執行,該函數會在程序停止運行的位置拋出 GeneratorExit 異常。

舉個例子:


 
  1. def foo():
  2. try:
  3. yield 1
  4. except GeneratorExit:
  5. print('捕獲到 GeneratorExit')
  6. f = foo()
  7. print(next(f))
  8. f.close()

程序執行結果爲:

1
捕獲到 GeneratorExit


注意,雖然通過捕獲 GeneratorExit 異常,可以繼續執行生成器函數中剩餘的代碼,帶這部分代碼中不能再包含 yield 語句,否則程序會拋出 RuntimeError 異常。例如:


 
  1. def foo():
  2. try:
  3. yield 1
  4. except GeneratorExit:
  5. print('捕獲到 GeneratorExit')
  6. yield 2 #拋出 RuntimeError 異常
  7.  
  8. f = foo()
  9. print(next(f))
  10. f.close()

程序執行結果爲:

1
捕獲到 GeneratorExit Traceback (most recent call last):
  File "D:\python3.6\1.py", line 10, in <module>
    f.close()
RuntimeError: generator ignored GeneratorExit


另外,生成器函數一旦使用 close() 函數停止運行,後續將無法再調用 next() 函數或者 __next__() 方法啓動執行,否則會拋出 StopIteration 異常。例如:


 
  1. def foo():
  2. yield "c.biancheng.net"
  3. print("生成器停止執行")
  4.  
  5. f = foo()
  6. print(next(f)) #輸出 "c.biancheng.net"
  7. f.close()
  8. next(f) #原本應輸出"生成器停止執行"

程序執行結果爲:

c.biancheng.net
Traceback (most recent call last):
  File "D:\python3.6\1.py", line 8, in <module>
    next(f) #原本應輸出"生成器停止執行"
StopIteration

Python生成器throw()方法

生成器 throw() 方法的功能是,在生成器函數執行暫停處,拋出一個指定的異常,之後程序會繼續執行生成器函數中後續的代碼,直到遇到下一個 yield 語句。需要注意的是,如果到剩餘代碼執行完畢沒有遇到下一個 yield 語句,則程序會拋出 StopIteration 異常。

舉個例子:


 
  1. def foo():
  2. try:
  3. yield 1
  4. except ValueError:
  5. print('捕獲到 ValueError')
  6.  
  7. f = foo()
  8. print(next(f))
  9. f.throw(ValueError)

程序執行結果爲:

1
捕獲到 ValueError
Traceback (most recent call last):
  File "D:\python3.6\1.py", line 9, in <module>
    f.throw(ValueError)
StopIteration

顯然,一開始生成器函數在 yield 1 處暫停執行,當執行 throw() 方法時,它會先拋出 ValueError 異常,然後繼續執行後續代碼找到下一個 yield 語句,該程序中由於後續不再有 yield 語句,因此程序執行到最後,會拋出一個 StopIteration 異常。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章