成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

動(dòng)態(tài)捕獲Python異常

開發(fā) 前端 后端
下面的代碼來自一個(gè)產(chǎn)品中看起來是好的抽象代碼 - slightly(!) .這是調(diào)用一些統(tǒng)計(jì)數(shù)據(jù)的函數(shù),然后進(jìn)行處理 . 首先是用socket連接獲取一個(gè)值,可能發(fā)生了socket錯(cuò)誤.由于統(tǒng)計(jì)數(shù)據(jù)在系統(tǒng)中不是至關(guān)重要的,我們只是記一下日志錯(cuò)誤并繼續(xù)往下走.

在討論動(dòng)態(tài)捕獲異常時(shí)讓我大吃一驚的是,可以讓我找到隱藏的Bug和樂趣...

有問題的代碼

下面的代碼來自一個(gè)產(chǎn)品中看起來是好的抽象代碼 - slightly(!) .這是調(diào)用一些統(tǒng)計(jì)數(shù)據(jù)的函數(shù),然后進(jìn)行處理 . 首先是用socket連接獲取一個(gè)值,可能發(fā)生了socket錯(cuò)誤.由于統(tǒng)計(jì)數(shù)據(jù)在系統(tǒng)中不是至關(guān)重要的,我們只是記一下日志錯(cuò)誤并繼續(xù)往下走.

(請(qǐng)注意,這篇文章我使用doctest測(cè)試的 - 這代表代碼可以運(yùn)行!)

  1. >>> def get_stats():  
  2. ...     pass 
  3. ...  
  4. >>> def do_something_with_stats(stats):  
  5. ...     pass 
  6. ...  
  7. >>> try:  
  8. ...     stats = get_stats()  
  9. ... except socket.error:  
  10. ...     logging.warning("Can't get statistics")  
  11. ... else:  
  12. ...     do_something_with_stats(stats)  

查找

我們測(cè)試時(shí)并沒有發(fā)現(xiàn)不妥, 但實(shí)際上我們注意到靜態(tài)分析報(bào)告顯示一個(gè)問題:

  1. $ flake8 filename.py  
  2. filename.py:351:1: F821 undefined name 'socket' 
  3. filename.py:352:1: F821 undefined name 'logging' 

顯然是我們沒測(cè)試,這個(gè)問題是代碼中我們沒有引用socket 和 logging 兩個(gè)模塊.使我感到驚奇的是,這并沒有預(yù)先拋出NameError錯(cuò),我以為它會(huì)查找這些異常語句中的一些名詞,如它需要捕捉這些異常,它需要知道些什么呢!

事實(shí)證明并非如此,異常語句的查找是延遲完成的,只是評(píng)估時(shí)拋出異常. 不只是名稱延遲查找,也可以定制顯示聲明異常做為'參數(shù)(argument)'.

這可能是好事,壞事,或者是令人厭惡的.

好事(上段中提到的)

異常參數(shù)可以以任意形式數(shù)值傳遞. 這樣就允許了異常的動(dòng)態(tài)參數(shù)被捕獲.

  1. >>> def do_something():  
  2. ...    blob  
  3. ...  
  4. >>> def attempt(action, ignore_spec):  
  5. ...     try:  
  6. ...         action()  
  7. ...     except ignore_spec:  
  8. ...         pass 
  9. ...  
  10. >>> attempt(do_something, ignore_spec=(NameError, TypeError))  
  11. >>> attempt(do_something, ignore_spec=TypeError)  
  12. Traceback (most recent call last):  
  13.   ...  
  14. NameError: global name 'blob' is not defined 

壞事(上段中提到的)

這種明顯的弊端就是異常參數(shù)中的錯(cuò)誤通常只有在異常觸發(fā)之后才會(huì)被注意到,不過為時(shí)已晚.當(dāng)用異常去捕獲不常見的事件時(shí)(例如:以寫方式打開文件失敗), 除非做個(gè)一個(gè)特定的測(cè)試用例,否則只有當(dāng)一個(gè)異常(或者任何異常)被觸發(fā)的時(shí)候才會(huì)知道, 屆時(shí)記錄下來并且查看是否有匹配的異常, 并且拋出它自己的錯(cuò)誤異常 - 這是一個(gè)NameError通常所做的事情.

  1. >>> def do_something():  
  2. ...     return 12 
  3. ...  
  4. >>> try:  
  5. ...     a, b = do_something()  
  6. ... except ValuError:  # oops - someone can't type  
  7. ...     print("Oops")  
  8. ... else:  
  9. ...     print("OK!")   # we are 'ok' until do_something returns a triple...  
  10. OK! 

令人討厭的(上段中提到的)

  1. >>> try:  
  2. ...    TypeError = ZeroDivisionError  # now why would we do this...?!  
  3. ...    1 / 0 
  4. ... except TypeError:  
  5. ...    print("Caught!")  
  6. ... else:  
  7. ...    print("ok")  
  8. ...  
  9. Caught! 

不僅僅是異常參數(shù)通過名稱查找, - 其它的表達(dá)式也是這樣工作的:

  1. >>> try:  
  2. ...     1 / 0 
  3. ... except eval(''.join('Zero Division Error'.split())):  
  4. ...     print("Caught!")  
  5. ... else:  
  6. ...     print("ok")  
  7. ...  
  8. Caught! 

異常參數(shù)不僅僅只能在運(yùn)行時(shí)確定,它甚至可以使用在生命周期內(nèi)的異常的信息. 以下是一個(gè)比較費(fèi)解的方式來捕捉拋出的異常 - 但也只能如此了:

  1. >>> import sys  
  2. >>> def current_exc_type():  
  3. ...     return sys.exc_info()[0]  
  4. ...  
  5. >>> try:  
  6. ...     blob  
  7. ... except current_exc_type():  
  8. ...     print ("Got you!")  
  9. ...  
  10. Got you! 

很明顯這才是我們真正要尋找的當(dāng)我們寫異常處理程序時(shí), 我們應(yīng)該首先想到的就是這種

(字節(jié))代碼

為了確認(rèn)它是如何在異常處理工作中出現(xiàn)的,我在一個(gè)異常的例子中運(yùn)行 dis.dis(). (注意 這里的分解是在Python2.7 下 - 不同的字節(jié)碼是Python 3.3下產(chǎn)生的,但這基本上是類似的):

  1. >>> import dis  
  2. >>> def x():  
  3. ...     try:  
  4. ...         pass 
  5. ...     except Blobbity:  
  6. ...         print("bad")  
  7. ...     else:  
  8. ...         print("good")  
  9. ...  
  10. >>> dis.dis(x)  # doctest: +NORMALIZE_WHITESPACE  
  11.   2           0 SETUP_EXCEPT             4 (to 7)  
  12. <BLANKLINE>  
  13.   3           3 POP_BLOCK  
  14.               4 JUMP_FORWARD            22 (to 29)  
  15. <BLANKLINE>  
  16.   4     >>    7 DUP_TOP  
  17.               8 LOAD_GLOBAL              0 (Blobbity)  
  18.              11 COMPARE_OP              10 (exception match)  
  19.              14 POP_JUMP_IF_FALSE       28 
  20.              17 POP_TOP  
  21.              18 POP_TOP  
  22.              19 POP_TOP  
  23. <BLANKLINE>  
  24.   5          20 LOAD_CONST               1 ('bad')  
  25.              23 PRINT_ITEM  
  26.              24 PRINT_NEWLINE  
  27.              25 JUMP_FORWARD             6 (to 34)  
  28.         >>   28 END_FINALLY  
  29. <BLANKLINE>  
  30.   7     >>   29 LOAD_CONST               2 ('good')  
  31.              32 PRINT_ITEM  
  32.              33 PRINT_NEWLINE  
  33.         >>   34 LOAD_CONST               0 (None)  
  34.              37 RETURN_VALUE 

這顯示出了我原來預(yù)期的問題(issue). 異常處理"看起來"完全是按照Python內(nèi)部機(jī)制在運(yùn)行. 這一步完全沒有必要知道關(guān)于后續(xù)的異常“捕獲”語句, 并且如果沒有異常拋出它們將被完全忽略了.SETUP_EXCEPT并不關(guān)心發(fā)生了什么, 僅僅是如果發(fā)生了異常, ***個(gè)處理程序應(yīng)該被評(píng)估,然后第二個(gè),以此類推.

每個(gè)處理程序都有兩部分組成: 獲得一個(gè)異常的規(guī)則, 和剛剛拋出的異常進(jìn)行對(duì)比. 一切都是延遲的, 一切看起來正如對(duì)你的逐行的代碼的預(yù)期一樣, 從解釋器的角度來考慮. 沒有任何聰明的事情發(fā)生了,只是突然使得它看起來非常聰明.

總結(jié)

雖然這種動(dòng)態(tài)的異常參數(shù)讓我大吃一驚, 但是這當(dāng)中包含很多有趣的應(yīng)用. 當(dāng)然去實(shí)現(xiàn)它們當(dāng)中的許多或許是個(gè)餿主意,呵呵

有時(shí)并不能總是憑直覺來確認(rèn)有多少Python特性的支持 - 例如 在類作用域內(nèi) 表達(dá)式和聲明都是被顯式接受的, (而不是函數(shù), 方法, 全局作用域),但是并不是所有的都是如此靈活的. 雖然(我認(rèn)為)那將是十分美好的, 表達(dá)式被禁止應(yīng)用于裝飾器 - 以下是Python語法錯(cuò)誤:

  1. @(lambda fn: fn)  
  2. def x():  
  3.    pass 

這個(gè)是嘗試動(dòng)態(tài)異常參數(shù)通過給定類型傳遞給***個(gè)異常的例子, 靜靜的忍受重復(fù)的異常:

  1. >>> class Pushover(object):  
  2. ...     exc_spec = set()  
  3. ...  
  4. ...     def attempt(self, action):  
  5. ...         try:  
  6. ...             return action()  
  7. ...         except tuple(self.exc_spec):  
  8. ...             pass 
  9. ...         except BaseException as e:  
  10. ...             self.exc_spec.add(e.__class__)  
  11. ...             raise 
  12. ...  
  13. >>> pushover = Pushover()  
  14. >>>  
  15. >>> for _ in range(4):  
  16. ...     try:  
  17. ...         pushover.attempt(lambda1 / 0)  
  18. ...     except:  
  19. ...         print ("Boo")  
  20. ...     else:  
  21. ...         print ("Yay!")  
  22. Boo  
  23. Yay!  
  24. Yay!  
  25. Yay! 

英文原文:The Dynamics of Catching Exceptions in Python

譯文連接:http://www.oschina.net/translate/the-dynamics-of-catching-exceptions-in-python

責(zé)任編輯:林師授 來源: OSCHINA編譯
相關(guān)推薦

2021-03-13 17:38:51

Python警告開發(fā)

2017-03-21 16:34:38

iOS捕獲異常

2021-09-26 09:40:25

React代碼前端

2022-08-16 10:44:11

Sentry前端異常

2015-02-03 14:45:55

android全局異常

2024-11-11 11:21:30

虛擬機(jī)Python跳轉(zhuǎn)表

2017-05-04 21:30:32

前端異常監(jiān)控捕獲方案

2022-11-28 07:35:52

前端錯(cuò)誤

2009-07-15 15:09:18

2010-03-10 14:34:52

Python異常處理

2023-12-06 09:27:46

Java程序

2021-01-31 11:47:08

C語言SetjmpLongjmp

2019-11-15 14:14:13

Python開發(fā)BaseExcepti

2023-08-10 13:46:48

前端資源優(yōu)化

2025-02-17 00:25:00

Winform開發(fā)

2010-03-10 13:59:40

Python異常處理

2024-12-09 12:00:00

Python編程數(shù)據(jù)類型轉(zhuǎn)換

2025-02-14 10:13:55

2025-01-06 07:15:00

深度學(xué)習(xí)動(dòng)態(tài)圖異常檢測(cè)人工智能

2009-02-25 10:34:57

異常處理體系Python
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 日韩欧美一区二区三区 | 国产精品美女久久久久久久网站 | 精品一级| 最新国产在线 | 在线成人免费视频 | 亚洲男人天堂 | 久艹网站 | 男女午夜免费视频 | 日韩精品在线一区 | 中文字幕在线观看av | 亚洲国产精品一区 | 国产第一页在线观看 | 天天爽夜夜爽精品视频婷婷 | 亚洲精品中文字幕在线观看 | 韩日免费视频 | 亚州综合在线 | 成人久久久 | 亚洲成人蜜桃 | 国产成人综合一区二区三区 | 最近最新中文字幕 | 国产91精品久久久久久久网曝门 | 伦理午夜电影免费观看 | 欧美日韩在线成人 | 国产高清精品在线 | 99精品久久久久久久 | 成人免费视频7777777 | 精品亚洲二区 | 久久久国产精品 | 亚洲三级免费看 | 日韩成人av在线 | 在线国产一区二区 | 国产精品久久在线 | 久久99蜜桃综合影院免费观看 | 久久精品一区 | 国产精品久久久久久久久久不蜜臀 | 国产一区二区三区在线视频 | 国产超碰人人爽人人做人人爱 | 欧美一区二区三区视频 | 黄网站免费在线观看 | 欧美成人一区二区三区 | 久久精品国产免费一区二区三区 |