python中終止協(xié)程和異常處理方式
協(xié)程中未處理的異常會(huì)向上冒泡,傳給 next 函數(shù)或 send 方法的調(diào)用方(即觸發(fā)協(xié)程的對(duì) 象)。
下面示例舉例說明如何使用之前博客示例中由裝飾器定義的 averager 協(xié)程。
未處理的異常會(huì)導(dǎo)致協(xié)程終止
""" 預(yù)激協(xié)程的裝飾器 """ from inspect import getgeneratorstate from functools import wraps def coroutine(func): ? ? """裝飾器:向前執(zhí)行到第一個(gè)`yield`表達(dá)式,預(yù)激`func`""" ? ? # 把被裝飾的生成器函數(shù)替換成這里的 primer 函數(shù); ? ? # 調(diào)用 primer 函數(shù)時(shí),返回預(yù)激后的 生成器。 ? ? @wraps(func) ? ? def primer(*args, **kwargs): ? ? ? ? # 調(diào)用被裝飾的函數(shù),獲取生成器對(duì)象。 ? ? ? ? gen = func(*args, **kwargs) ? ? ? ? # 預(yù)激生成器。 ? ? ? ? next(gen) ? ? ? ? # 返回生成器。 ? ? ? ? return gen ? ? return primer @coroutine def averager(): ? ? total = 0.0 ? ? count = 0 ? ? average = None ? ? while True: ? ? ? ? term = yield average ? ? ? ? total += term ? ? ? ? count += 1 ? ? ? ? average = total / count if __name__ == '__main__': ? ? coro_avg = averager() ? ? # print(getgeneratorstate(coro_avg)) ? ? print(coro_avg.send(10)) ? ? print(coro_avg.send(30)) ? ? # 發(fā)送的值不是數(shù)字,導(dǎo)致協(xié)程內(nèi)部有異常拋出。 ? ? print(coro_avg.send('spam')) ? ? # 由于在協(xié)程內(nèi)沒有處理異常,協(xié)程會(huì)終止。 ? ? # 如果試圖重新激活協(xié)程,會(huì)拋出 StopIteration 異常。 ? ? print(coro_avg.send(60))
上面示例,暗示了終止協(xié)程的一種方式:發(fā)送某個(gè)哨符值,讓協(xié)程退出。內(nèi)置的 None 和 Ellipsis 等常量經(jīng)常用作哨符值。Ellipsis 的優(yōu)點(diǎn)是,數(shù)據(jù)流中不太常有這個(gè)值。我還見 過有人把 StopIteration 類(類本身,而不是實(shí)例,也不拋出)作為哨符值;也就是說, 是像這樣使用的:my_coro.send(StopIteration)。
從 Python 2.5 開始,客戶代碼可以在生成器對(duì)象上調(diào)用兩個(gè)方法,顯式地把異常發(fā)給協(xié)程。
這兩個(gè)方法是 throw 和 close。
generator.throw(exc_type[, exc_value[, traceback]])
致使生成器在暫停的 yield 表達(dá)式處拋出指定的異常。
如果生成器處理了拋出的異常,代碼會(huì)向前執(zhí)行到下一個(gè) yield 表達(dá)式,而產(chǎn)出的值會(huì)成為調(diào)用 generator.throw 方法 得到的返回值。
如果生成器沒有處理拋出的異常,異常會(huì)向上冒泡,傳到調(diào)用方的上下 文中。
generator.close()
致使生成器在暫停的yield 表達(dá)式處拋出GeneratorExit 異常。
如果生成器沒有處 理這個(gè)異常,或者拋出了StopIteration 異常(通常是指運(yùn)行到結(jié)尾),調(diào)用方不會(huì) 報(bào)錯(cuò)。
如果收到GeneratorExit 異常,生成器一定不能產(chǎn)出值,否則解釋器會(huì)拋出 RuntimeError 異常。
生成器拋出的其他異常會(huì)向上冒泡,傳給調(diào)用方。
下面舉例說明
如何使用 close 和 throw 方法控制協(xié)程:
""" 學(xué)習(xí)在協(xié)程中處理異常的測(cè)試代碼 """ from inspect import getgeneratorstate class DemoException(Exception): ? ? """為這次演示定義的異常類型。""" def demo_exc_handling(): ? ? print('-> coroutine started') ? ? try: ? ? ? ? while True: ? ? ? ? ? ? try: ? ? ? ? ? ? ? ? x = yield ? ? ? ? ? ? # ?特別處理 DemoException 異常 ? ? ? ? ? ? except DemoException: ? ? ? ? ? ? ? ? print('*** DemoException handled. Continuing...') ? ? ? ? ? ? # 如果沒有異常,那么顯示接收到的值。 ? ? ? ? ? ? else: ? ? ? ? ? ? ? ? print('-> coroutine received: {!r}'.format(x)) ? ? finally: ? ? ? ? # 如果不管協(xié)程如何結(jié)束都想做些清理工作, ? ? ? ? # 要把協(xié)程定義體中相關(guān)的代碼放入try/ finally 塊中 ? ? ? ? print('-> coroutine ending') if __name__ == '__main__': ? ? exc_coro = demo_exc_handling() ? ? next(exc_coro) ? ? exc_coro.send(11) ? ? exc_coro.send(22) ? ? # 激活和關(guān)閉 demo_exc_handling,沒有異常 ? ? # exc_coro.close() ? ? # 如果把 DemoException 異常傳入 demo_exc_handling 協(xié)程, ? ? # 它會(huì)處理,然后繼續(xù)運(yùn)行 ? ? # exc_coro.throw(DemoException) ? ? # exc_coro.send(33) ? ? # 如果無法處理傳入的異常,協(xié)程會(huì)終止 ? ? exc_coro.throw(ZeroDivisionError) ? ? print(getgeneratorstate(exc_coro))
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
對(duì)Python 窗體(tkinter)樹狀數(shù)據(jù)(Treeview)詳解
今天小編就為大家分享一篇對(duì)Python 窗體(tkinter)樹狀數(shù)據(jù)(Treeview)詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-10-10使用OpenCV獲取圖片連通域數(shù)量,并用不同顏色標(biāo)記函
這篇文章主要介紹了使用OpenCV獲取圖片連通域數(shù)量,并用不同顏色標(biāo)記函,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-06-06numpy 對(duì)矩陣中Nan的處理:采用平均值的方法
今天小編就為大家分享一篇numpy 對(duì)矩陣中Nan的處理:采用平均值的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-10-10python使用 zip 同時(shí)迭代多個(gè)序列示例
這篇文章主要介紹了python使用 zip 同時(shí)迭代多個(gè)序列,結(jié)合實(shí)例形式分析了Python使用zip遍歷迭代長(zhǎng)度相等與不等的序列相關(guān)操作技巧,需要的朋友可以參考下2019-07-07Python Flask異步發(fā)送郵件實(shí)現(xiàn)方法解析
這篇文章主要介紹了Python Flask異步發(fā)送郵件實(shí)現(xiàn)方法解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08Python爬取網(wǎng)易云音樂上評(píng)論火爆的歌曲
最近跟著網(wǎng)上教程學(xué)著用python爬取問題,于是就想試著扒一扒Python爬取網(wǎng)易云音樂上評(píng)論火爆的歌曲,下面這篇文章就主要介紹了利用Python如何爬取網(wǎng)易云音樂上那些評(píng)論火爆的歌曲,需要的朋友可以參考借鑒,一起來看看吧。2017-01-01python基于pygame實(shí)現(xiàn)飛機(jī)大作戰(zhàn)小游戲
這篇文章主要為大家詳細(xì)介紹了python基于pygame實(shí)現(xiàn)飛機(jī)大作戰(zhàn)小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-11-11python 使用事件對(duì)象asyncio.Event來同步協(xié)程的操作
這篇文章主要介紹了python 使用事件對(duì)象asyncio.Event來同步協(xié)程的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-05-05