python throw_Python 生成器与它的 send,throw,close 方法(转帖以及记录)
Python 生成器與它的 send,throw,close 方法
在生成器中,無論生成器是什么狀態,都可以直接使用throw與close。
生成器這一塊,對于next,send網上的介紹比較多,但對于throw以及close很多書上寫的比較少,可能用的比較少,好在網上有很多介紹。
以下是流暢的Python對throw和close的介紹:
generator.throw(exc_type[, exc_value[, traceback]])
致使生成器在暫停的yield表達式處拋出指定的異常。如果生成器處理了拋出的異常,代碼會向前執行到下一個yield表達式,而產出的值會調用generator.throw方法得到的返回值。如果生成器沒有處理拋出的異常,異常會向上冒泡,傳到調用方的上下文中。
generator.close()
致使生成器在暫停的yield表達式處拋出GeneratorExit異常。如果生成器沒有處理這個異常,或者拋出了StopIteration異常(通常是指運行到結尾),調用方不會報錯。如果收到GeneratorExit異常,生成器一定不能產出值,否則解釋器會拋出RuntimeError異常。生成器拋出的其他異常會向上冒泡,傳給調用方。
next就是send(None)
生成器第一次需要預激,到達第一個yield處,預激可以用next或send(None),預激將產出第一個值,并到達第一個yield處
到達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:
簡單的測試了next與send,接著測試throw.
按照前面書中的說明,throw以后如果抓取到錯誤,執行except內的語句,然后尋找下一個yield,所以如果在最后一個yield處throw,就算抓取在生成器中抓取到錯誤也會上浮錯誤信息
StopIteration。當throw進去一個錯誤,生成器內部沒有處理,當外部調用生成器的時候捕獲了上浮的錯誤,此時生成器已經關閉,如果再次使用next與send會包stopIteration。
(這里我重點筆記一下throw(StopIteration),因為當throw這個的時候,報的錯誤是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]:
上面這個是普通的沒有去獲取任何異常的情況下,可以發現,生成器沒有預激的情況下,也可以throw錯誤,只不過上浮的錯誤顯示,報錯的方位不一樣。
沒有預激的生成器在def處就發現了錯誤,預激的生成器在第一個yield處發生了錯誤。
我測試了很多不同的錯誤,一般不管在預激還是沒有預激的情況下,扔什么錯誤,在沒有捕獲的情況下,就上浮錯誤,但StopIterations是一個例外。
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:
上面是一個沒有捕獲錯誤,外部捕獲了錯誤,但生成器已經關閉了。
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]:
上面的例子測試了沒有預激的情況下,throw錯誤,生成器內部完全不能捕獲任何沒有預激情況下的錯誤,而且該生成器也將關閉。
在預激的情況下,可以捕獲設置的錯誤,并且尋找下一個yield,如果沒有下一個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]:
從上面的列子可以看出只要沒有捕獲StopItoration,就上浮RuntimeError,而且這個錯誤是就因為StopItoration引起的。
但如果在生成器內部預設了捕獲StopItoration,則還是跟不同的邏輯是一樣的。
我的理解為,應該為如果沒有捕獲StopItoration,直接用了什么方法調用生成了新的錯誤,上浮給調用者,避免與StopItoration錯誤重復。
最后是close,按照書中的說法跟我自己的理解,就是在yield處拋出Generation,可以通過except捕獲到錯誤,但捕獲了以后,后面不能再有yield產出值,要不然包RuntimeError。
就算不捕獲也沒關系,不會上浮任何的錯誤,只不過該協程已經關閉了。
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
最后,我自己總結一下thorw與close的筆記,兩個函數都可以不需要預激的情況下面執行。
但執行的時候,生成器內部不會捕獲到該異常。
預激了以后,throw所有的異常都能捕獲,捕獲到該異常后,向下執行尋找下一個yield,產出值,沒有yield就上浮StopItoration
close在預激了以后,能通過except捕獲到該GeneratorExit異常,但except向下的代碼不能出現yield產出值,要不然會拋出RuntimeError。
如果throw(StopItoration),如果沒有捕獲該錯誤,上浮的錯誤為RuntimeError。
一個生成器關閉了,還能繼續使用close函數,且不會報錯。
最后,一個生成器內部如果發生錯誤,沒有捕獲,這個生成器就馬上進行關閉。
總結
以上是生活随笔為你收集整理的python throw_Python 生成器与它的 send,throw,close 方法(转帖以及记录)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python访问网页时401_在pyth
- 下一篇: redis value多大会影响性能_事