從語法上看缘琅,協(xié)程與生成器類似粘都。但是協(xié)程中,yield通常出現(xiàn)在表達式的右邊(例如胯杭, datum = yield)驯杜。協(xié)程可以從調(diào)用方接受數(shù)據(jù),如.send(datum)方法做个。要理解協(xié)程鸽心,需要從根本上把yield視作控制流程的方式。
生成器如何進化為協(xié)程
- 添加了.send(...), .throw(...),.close()方法居暖。
用作協(xié)程的生成器的基本行為
協(xié)程可以處于四個狀態(tài)中的一個顽频,當前狀態(tài)可以使用inspect.getgeneratorstat(...)函數(shù)確定
- GEN_CREATED:等待開始執(zhí)行
- GEN_RUNNING:解釋器正在執(zhí)行
- GEN_SUSPENDED: 在yield表達式處暫停
-
GEN_CLOSED: 執(zhí)行結束
只有當處于暫停狀態(tài)時才能調(diào)用send方法。
預激協(xié)程的裝飾器
如果不預激(使用next首次啟動協(xié)程太闺,到達yield處停止),協(xié)程沒什么用.我們可以使用一個預激裝飾器
from functools import wraps
def coroutine(func):
@wraps(func)
def primer(*args,**kwargs):
gen = func(*args, **kwargs)
next(gen)
return gen
return primer
終止協(xié)程和異常處理
協(xié)程中未出率的異常會向上拋出糯景,傳給next函數(shù)或者send方法的調(diào)用方(即觸發(fā)協(xié)程的對象)。
- generator.throw(): 讓生成器在暫停的yield表達式處拋出指定的異常,如果生成器處理了異常蟀淮,代碼繼續(xù)向前執(zhí)行到下一個yield表達式最住。產(chǎn)出的值會成為該調(diào)用方法的返回值。如果生成器中沒有處理異常怠惶,向上拋出異常涨缚,傳到調(diào)用方的上下文中。
- generator.close():致使生成器在暫停的yield表達式處拋出GeneratorExit異常策治。
讓協(xié)程返回值
協(xié)程的返回值return表達式的值會偷偷的傳給調(diào)用方脓魏,賦值給StopIteration異常的一個屬性。獲取該屬性可以從異常的value中拿到通惫。
其實茂翔,yield from 結構跟for循環(huán)處理StopIteration異常的方式一樣。解釋器不僅會捕獲StopIteration異常履腋,還會把value屬性的值變?yōu)閥ield from表達式的值珊燎。