python throw_Python 生成器与它的 send,throw,close 方法(转帖以及记录)
Python 生成器與它的 send,throw,close 方法
在生成器中,無(wú)論生成器是什么狀態(tài),都可以直接使用throw與close。
生成器這一塊,對(duì)于next,send網(wǎng)上的介紹比較多,但對(duì)于throw以及close很多書(shū)上寫(xiě)的比較少,可能用的比較少,好在網(wǎng)上有很多介紹。
以下是流暢的Python對(duì)throw和close的介紹:
generator.throw(exc_type[, exc_value[, traceback]])
致使生成器在暫停的yield表達(dá)式處拋出指定的異常。如果生成器處理了拋出的異常,代碼會(huì)向前執(zhí)行到下一個(gè)yield表達(dá)式,而產(chǎn)出的值會(huì)調(diào)用generator.throw方法得到的返回值。如果生成器沒(méi)有處理拋出的異常,異常會(huì)向上冒泡,傳到調(diào)用方的上下文中。
generator.close()
致使生成器在暫停的yield表達(dá)式處拋出GeneratorExit異常。如果生成器沒(méi)有處理這個(gè)異常,或者拋出了StopIteration異常(通常是指運(yùn)行到結(jié)尾),調(diào)用方不會(huì)報(bào)錯(cuò)。如果收到GeneratorExit異常,生成器一定不能產(chǎn)出值,否則解釋器會(huì)拋出RuntimeError異常。生成器拋出的其他異常會(huì)向上冒泡,傳給調(diào)用方。
next就是send(None)
生成器第一次需要預(yù)激,到達(dá)第一個(gè)yield處,預(yù)激可以用next或send(None),預(yù)激將產(chǎn)出第一個(gè)值,并到達(dá)第一個(gè)yield處
到達(dá)yield處可以send(object)了。
In [319]: def demo():
...: for i in range(5):
...: res = yield i
...: print(res)
...:
In [320]: d = demo()
In [321]: type(d)
Out[321]: generator
In [322]: next(d)
Out[322]: 0
In [323]: d.send('ok')
ok
Out[323]: 1
In [324]: d.send(None)
None
Out[324]: 2
In [325]: next(d)
None
Out[325]: 3
In [326]: next(d)
None
Out[326]: 4
In [327]: next(d)
None
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
in
----> 1 next(d)
StopIteration:
In [328]: next(d)
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
in
----> 1 next(d)
StopIteration:
簡(jiǎn)單的測(cè)試了next與send,接著測(cè)試throw.
按照前面書(shū)中的說(shuō)明,throw以后如果抓取到錯(cuò)誤,執(zhí)行except內(nèi)的語(yǔ)句,然后尋找下一個(gè)yield,所以如果在最后一個(gè)yield處throw,就算抓取在生成器中抓取到錯(cuò)誤也會(huì)上浮錯(cuò)誤信息
StopIteration。當(dāng)throw進(jìn)去一個(gè)錯(cuò)誤,生成器內(nèi)部沒(méi)有處理,當(dāng)外部調(diào)用生成器的時(shí)候捕獲了上浮的錯(cuò)誤,此時(shí)生成器已經(jīng)關(guān)閉,如果再次使用next與send會(huì)包stopIteration。
(這里我重點(diǎn)筆記一下throw(StopIteration),因?yàn)楫?dāng)throw這個(gè)的時(shí)候,報(bào)的錯(cuò)誤是RuntimeError)
In [1]: def xx():
...: yield 1
...:
In [2]: x = xx()
In [3]: x.throw(NameError)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
in
----> 1 x.throw(NameError)
in xx()
----> 1 def xx():
2 yield 1
3
NameError:
In [4]: x = xx()
In [5]: next(x)
Out[5]: 1
In [6]: x.throw(NameError)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
in
----> 1 x.throw(NameError)
in xx()
1 def xx():
----> 2 yield 1
3
NameError:
In [7]:
上面這個(gè)是普通的沒(méi)有去獲取任何異常的情況下,可以發(fā)現(xiàn),生成器沒(méi)有預(yù)激的情況下,也可以throw錯(cuò)誤,只不過(guò)上浮的錯(cuò)誤顯示,報(bào)錯(cuò)的方位不一樣。
沒(méi)有預(yù)激的生成器在def處就發(fā)現(xiàn)了錯(cuò)誤,預(yù)激的生成器在第一個(gè)yield處發(fā)生了錯(cuò)誤。
我測(cè)試了很多不同的錯(cuò)誤,一般不管在預(yù)激還是沒(méi)有預(yù)激的情況下,扔什么錯(cuò)誤,在沒(méi)有捕獲的情況下,就上浮錯(cuò)誤,但StopIterations是一個(gè)例外。
In [33]: def xx():
...: yield 1
...: yield 2
...:
In [34]: x = xx()
In [35]: next(x)
Out[35]: 1
In [37]: try:
...: x.throw(ValueError,'ValueError_my')
...: except ValueError as e:
...: print(e)
...:
ValueError_my
In [38]: inspect.getgeneratorstate(x)
Out[38]: 'GEN_CLOSED'
In [39]: next(x)
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
in
----> 1 next(x)
StopIteration:
上面是一個(gè)沒(méi)有捕獲錯(cuò)誤,外部捕獲了錯(cuò)誤,但生成器已經(jīng)關(guān)閉了。
In [40]: def xx():
...: try:
...: yield 1
...: yield 2
...: except TypeError:
...: print('info type error')
...:
...:
In [41]: x = xx()
In [42]: x.throw(TypeError)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
in
----> 1 x.throw(TypeError)
in xx()
----> 1 def xx():
2 try:
3 yield 1
4 yield 2
5 except TypeError:
TypeError:
In [43]: x = xx()
In [44]: next(x)
Out[44]: 1
In [45]: x.throw(TypeError)
info type error
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
in
----> 1 x.throw(TypeError)
StopIteration:
In [46]: def xx():
...: try:
...: yield 1
...: yield 2
...: except TypeError:
...: print('info type error')
...: yield 3
...:
...:
...:
In [47]: x = xx()
In [48]: next(x)
Out[48]: 1
In [49]: x.throw(TypeError)
info type error
Out[49]: 3
In [50]: next(x)
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
in
----> 1 next(x)
StopIteration:
In [51]:
上面的例子測(cè)試了沒(méi)有預(yù)激的情況下,throw錯(cuò)誤,生成器內(nèi)部完全不能捕獲任何沒(méi)有預(yù)激情況下的錯(cuò)誤,而且該生成器也將關(guān)閉。
在預(yù)激的情況下,可以捕獲設(shè)置的錯(cuò)誤,并且尋找下一個(gè)yield,如果沒(méi)有下一個(gè)yield,上浮StopIteration
In [54]: def xx():
...: try:
...: yield 1
...: yield 2
...: except StopIteration:
...: print('info stop')
...: yield 3
...:
...:
...:
In [55]: x = xx()
In [56]: x.throw(StopIteration)
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
in xx()
----> 1 def xx():
2 try:
3 yield 1
StopIteration:
The above exception was the direct cause of the following exception:
RuntimeError Traceback (most recent call last)
in
----> 1 x.throw(StopIteration)
RuntimeError: generator raised StopIteration
In [57]: x = xx()
In [58]: next(x)
Out[58]: 1
In [59]: x.throw(StopIteration)
info stop
Out[59]: 3
In [60]: x.throw(StopIteration)
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
in xx()
6 print('info stop')
----> 7 yield 3
8
StopIteration:
The above exception was the direct cause of the following exception:
RuntimeError Traceback (most recent call last)
in
----> 1 x.throw(StopIteration)
RuntimeError: generator raised StopIteration
In [61]:
從上面的列子可以看出只要沒(méi)有捕獲StopItoration,就上浮RuntimeError,而且這個(gè)錯(cuò)誤是就因?yàn)镾topItoration引起的。
但如果在生成器內(nèi)部預(yù)設(shè)了捕獲StopItoration,則還是跟不同的邏輯是一樣的。
我的理解為,應(yīng)該為如果沒(méi)有捕獲StopItoration,直接用了什么方法調(diào)用生成了新的錯(cuò)誤,上浮給調(diào)用者,避免與StopItoration錯(cuò)誤重復(fù)。
最后是close,按照書(shū)中的說(shuō)法跟我自己的理解,就是在yield處拋出Generation,可以通過(guò)except捕獲到錯(cuò)誤,但捕獲了以后,后面不能再有yield產(chǎn)出值,要不然包RuntimeError。
就算不捕獲也沒(méi)關(guān)系,不會(huì)上浮任何的錯(cuò)誤,只不過(guò)該協(xié)程已經(jīng)關(guān)閉了。
In [61]: def xx():
...: try:
...: yield 1
...: yield 2
...: except GeneratorExit:
...: print('info stop')
...: yield 3
...:
...:
...:
...:
In [62]: x= xx()
In [63]: x.close()
In [64]: next(x)
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
in
----> 1 next(x)
StopIteration:
In [65]: x= xx()
In [66]: next(x)
Out[66]: 1
In [67]: x.close()
info stop
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
in
----> 1 x.close()
RuntimeError: generator ignored GeneratorExit
In [68]: x= xx()
In [69]: next(x)
Out[69]: 1
In [70]: x.throw(GeneratorExit)
info stop
Out[70]: 3
最后,我自己總結(jié)一下thorw與close的筆記,兩個(gè)函數(shù)都可以不需要預(yù)激的情況下面執(zhí)行。
但執(zhí)行的時(shí)候,生成器內(nèi)部不會(huì)捕獲到該異常。
預(yù)激了以后,throw所有的異常都能捕獲,捕獲到該異常后,向下執(zhí)行尋找下一個(gè)yield,產(chǎn)出值,沒(méi)有yield就上浮StopItoration
close在預(yù)激了以后,能通過(guò)except捕獲到該GeneratorExit異常,但except向下的代碼不能出現(xiàn)yield產(chǎn)出值,要不然會(huì)拋出RuntimeError。
如果throw(StopItoration),如果沒(méi)有捕獲該錯(cuò)誤,上浮的錯(cuò)誤為RuntimeError。
一個(gè)生成器關(guān)閉了,還能繼續(xù)使用close函數(shù),且不會(huì)報(bào)錯(cuò)。
最后,一個(gè)生成器內(nèi)部如果發(fā)生錯(cuò)誤,沒(méi)有捕獲,這個(gè)生成器就馬上進(jìn)行關(guān)閉。
總結(jié)
以上是生活随笔為你收集整理的python throw_Python 生成器与它的 send,throw,close 方法(转帖以及记录)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: python访问网页时401_在pyth
- 下一篇: redis value多大会影响性能_事