摘要:下面我們來(lái)看一下效果下次需要捕獲一個(gè)異常然后再拋出另一個(gè)異常的時(shí)候大家可以試試本文的方法。
一般實(shí)現(xiàn)捕獲異常然后再拋出另一個(gè)異常的方法類(lèi)似下面這樣:
def div(): 2 / 0 try: div() except ZeroDivisionError as e: raise ValueError(e)
不知道大家有沒(méi)有注意到這樣拋出異常的方式有一個(gè)很?chē)?yán)重的問(wèn)題,那就是 在重新拋出另一個(gè)異常的時(shí)候,捕獲的上一個(gè)異常的 traceback 信息丟失了(python2): :
$ cat a.py def div(): 2 / 0 try: div() except ZeroDivisionError as e: raise ValueError(e) $ python2 a.py Traceback (most recent call last): File "a.py", line 6, inraise ValueError(e) ValueError: integer division or modulo by zero
這樣的話非常不利于查找問(wèn)題: 比如上面的例子中實(shí)際出錯(cuò)的代碼是第二行,但是 當(dāng)我們捕獲了第一個(gè)異常然后再拋出一個(gè)自定義異常的時(shí)候, 實(shí)際出錯(cuò)位置的信息就丟失了。
Python 2那么在 Python 2 下如果我們不想丟失捕獲的異常的 traceback 信息的話,應(yīng)該 怎樣重新拋出異常呢?
有兩種辦法, 還是用上面的例子舉例:
一種辦法是直接 raise: :
$ cat a.py def div(): 2 / 0 try: div() except ZeroDivisionError as e: raise $ python2 a.py Traceback (most recent call last): File "a.py", line 4, indiv() File "a.py", line 2, in div 2 / 0 ZeroDivisionError: integer division or modulo by zero
另一種辦法就是 raise 另一個(gè)異常時(shí)指定上一個(gè)異常的 traceback 信息 (通過(guò) sys.exc_info() 獲取當(dāng)前捕獲的異常信息): :
$ cat a.py import sys def div(): 2 / 0 try: div() except ZeroDivisionError as e: raise ValueError(e), None, sys.exc_info()[2] $ python2 a.py Traceback (most recent call last): File "a.py", line 6, indiv() File "a.py", line 4, in div 2 / 0 ValueError: integer division or modulo by zero
這個(gè)是 raise 的高級(jí)用法:
raise exception, value, traceback
exception: 異常類(lèi)實(shí)例/異常類(lèi)
value: 初始化異常類(lèi)的參數(shù)值/異常類(lèi)實(shí)例(使用這個(gè)實(shí)例作為 raise 的異常實(shí)例)/元組/None
traceback: traceback 對(duì)象/None
下面我們來(lái)看看上面的方法是否可以應(yīng)對(duì)多層異常捕獲然后再拋出的情況: :
$ cat a.py import sys def div(): 2 / 0 def foo(): try: div() except ZeroDivisionError as e: raise ValueError(e), None, sys.exc_info()[2] def bar(): try: foo() except ValueError as e: raise TypeError(e), None, sys.exc_info()[2] def foobar(): try: bar() except TypeError as e: raise foobar() $ python2 a.py Traceback (most recent call last): File "a.py", line 23, infoobar() File "a.py", line 20, in foobar bar() File "a.py", line 14, in bar foo() File "a.py", line 8, in foo div() File "a.py", line 4, in div 2 / 0 TypeError: integer division or modulo by zero
從上面的結(jié)果可以看到這兩種方法是支持多層異常 traceback 信息傳遞的。
那么在 Python 3 下又怎么解決這個(gè)問(wèn)題呢?
Python 3在 Python 3 下默認(rèn)會(huì)附加上捕獲的上個(gè)異常的 trackback 信息(保存在異常實(shí)例的 __traceback__ 屬性中): :
$ cat a.py def div(): 2 / 0 try: div() except ZeroDivisionError as e: raise ValueError(e) $ python3 a.py Traceback (most recent call last): File "a.py", line 4, indiv() File "a.py", line 2, in div 2 / 0 ZeroDivisionError: division by zero During handling of the above exception, another exception occurred: Traceback (most recent call last): File "a.py", line 6, in raise ValueError(e) ValueError: division by zero
也支持指定使用哪個(gè)異常實(shí)例的 traceback 信息: raise ... from ... :
$ cat a.py def div(): 2 / 0 try: div() except ZeroDivisionError as e: raise ValueError(e) from e $ python a.py Traceback (most recent call last): File "a.py", line 5, indiv() File "a.py", line 2, in div 2 / 0 ZeroDivisionError: division by zero The above exception was the direct cause of the following exception: Traceback (most recent call last): File "a.py", line 7, in raise ValueError(e) from e ValueError: division by zero
也可以指定使用的 traceback 對(duì)象: raise exception.with_traceback(traceback) :
$ cat a.py import sys def div(): 2 / 0 try: div() except ZeroDivisionError as e: raise ValueError(e).with_traceback(sys.exc_info()[2]) $ python a.py Traceback (most recent call last): File "a.py", line 7, in兼容 Python 2 和 Python 3 的寫(xiě)法div() File "a.py", line 4, in div 2 / 0 ZeroDivisionError: division by zero During handling of the above exception, another exception occurred: Traceback (most recent call last): File "a.py", line 9, in raise ValueError(e).with_traceback(sys.exc_info()[2]) File "a.py", line 7, in div() File "a.py", line 4, in div 2 / 0 ValueError: division by zero
上面介紹了在 Python 2 和 Python 3 下的不同解決辦法,那么如何寫(xiě)一個(gè)兼容 Python 2 和 Python 3 的 reraise 函數(shù)呢?
下面將介紹一種方法:
PY3 = sys.version_info[0] == 3 if PY3: def reraise(tp, value, tb=None): if value.__traceback__ is not tb: raise value.with_traceback(tb) else: raise value else: exec("""def reraise(tp, value, tb=None): raise tp, value, tb """)
這里的 reraise 函數(shù)我們約定了 vlaue 參數(shù)的值是一個(gè)異常類(lèi)的實(shí)例。 上面 else 中之所以用 exec 去定義 reraise 函數(shù)是因?yàn)?raise tp, value, tb 在 Python 3 下會(huì)報(bào)語(yǔ)法錯(cuò)誤,所以用 exec 來(lái) 繞過(guò) Python 3 下的語(yǔ)法錯(cuò)誤檢查。
下面我們來(lái)看一下效果: :
$ cat a.py ef div(): 2 / 0 def foo(): try: div() except ZeroDivisionError as e: reraise(ValueError, ValueError(e), sys.exc_info()[2]) def bar(): try: foo() except ValueError as e: reraise(TypeError, TypeError(e), sys.exc_info()[2]) def foobar(): try: bar() except TypeError: raise foobar()
Python 2: :
$ python2 a.py Traceback (most recent call last): File "a.py", line 34, infoobar() File "a.py", line 31, in foobar bar() File "a.py", line 27, in bar reraise(TypeError, TypeError(e), sys.exc_info()[2]) File "a.py", line 25, in bar foo() File "a.py", line 21, in foo reraise(ValueError, ValueError(e), sys.exc_info()[2]) File "a.py", line 19, in foo div() File "a.py", line 15, in div 2 / 0 TypeError: integer division or modulo by zero
Python 3: :
$ python3 a.py Traceback (most recent call last): File "a.py", line 19, in foo div() File "a.py", line 15, in div 2 / 0 ZeroDivisionError: division by zero During handling of the above exception, another exception occurred: Traceback (most recent call last): File "a.py", line 25, in bar foo() File "a.py", line 21, in foo reraise(ValueError, ValueError(e), sys.exc_info()[2]) File "a.py", line 6, in reraise raise value.with_traceback(tb) File "a.py", line 19, in foo div() File "a.py", line 15, in div 2 / 0 ValueError: division by zero During handling of the above exception, another exception occurred: Traceback (most recent call last): File "a.py", line 34, infoobar() File "a.py", line 31, in foobar bar() File "a.py", line 27, in bar reraise(TypeError, TypeError(e), sys.exc_info()[2]) File "a.py", line 6, in reraise raise value.with_traceback(tb) File "a.py", line 25, in bar foo() File "a.py", line 21, in foo reraise(ValueError, ValueError(e), sys.exc_info()[2]) File "a.py", line 6, in reraise raise value.with_traceback(tb) File "a.py", line 19, in foo div() File "a.py", line 15, in div 2 / 0 TypeError: division by zero
下次需要捕獲一個(gè)異常然后再拋出另一個(gè)異常的時(shí)候大家可以試試本文的方法。
參考資料6. Simple statements — Python 2.7.12 documentation
6. Built-in Exceptions — Python 2.7.12 documentation
7. Simple statements — Python 3.5.2 documentation
5. Built-in Exceptions — Python 3.5.2 documentation
PEP 3109 -- Raising Exceptions in Python 3000 | Python.org
bottle/bottle.py at cafc15419cbb4a6cb748e6ecdccf92893bb25ce5 · bottlepy/bottle
flask/_compat.py at 6e46d0cd3969f6c13ff61c95c81a975192232fed · pallets/flask
原文地址: https://mozillazg.com/2016/08...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/38180.html
摘要:我們使用單元測(cè)試來(lái)驗(yàn)證一下我們使用了配合做單元測(cè)試。我們編寫(xiě)相應(yīng)的單元測(cè)試你會(huì)發(fā)現(xiàn),如果出現(xiàn)異常,只是簡(jiǎn)單的返回。但是在上面異常拋出的時(shí)候,解釋器已經(jīng)不在中了,因此無(wú)法被捕獲。 譯者按: 錯(cuò)誤是無(wú)法避免的,妥善處理它才是最重要的! 原文: A Guide to Proper Error Handling in JavaScript Related Topics: 譯者: Funde...
摘要:一旦異常被拋出,就表明錯(cuò)誤已無(wú)法挽回,也不能回來(lái)繼續(xù)執(zhí)行。這種在編譯時(shí)被強(qiáng)制檢查的異常稱為被檢查的異常。通過(guò)獲取原始異常。構(gòu)造器對(duì)于在構(gòu)造階段可能會(huì)拋出異常,并要求清理的類(lèi),最安全的做法是使用嵌套的子句。 點(diǎn)擊進(jìn)入我的博客 Java異常處理的目的在于通過(guò)使用少于目前數(shù)量的代碼來(lái)簡(jiǎn)化大型、可靠的程序的生成,并且通過(guò)這種方式可以使你更自信:你的應(yīng)用中沒(méi)有未處理的錯(cuò)誤。 12.1 概念 異...
摘要:如何良好的在代碼中設(shè)計(jì)異常機(jī)制本身設(shè)計(jì)的出發(fā)點(diǎn)是極好的,通過(guò)編譯器的強(qiáng)制捕獲,可以明確提醒調(diào)用者處理異常情況。但使用此種異常后,該會(huì)像病毒一樣,得不到處理后會(huì)污染大量代碼,同時(shí)也可能因?yàn)檎{(diào)用者的不當(dāng)處理,會(huì)失去異常信息。 1、異常是什么? 父類(lèi)為T(mén)hrowable,有Error和Exception兩個(gè)子類(lèi) Error為系統(tǒng)級(jí)別的異常(錯(cuò)誤) Exception下有眾多子類(lèi),常見(jiàn)的有Ru...
摘要:而異??梢圆槐伙@式的處理都是的子類(lèi),繼承了的就是異常,其他的就是異常。常見(jiàn)異常類(lèi)列舉幾個(gè)常見(jiàn)的運(yùn)行時(shí)異常數(shù)組越界異常空指針異常類(lèi)轉(zhuǎn)換異常數(shù)字格式異常運(yùn)算異常。 Java異常 java異常分為兩大類(lèi),Checked異常和Runtime異常,Checked異常都是在編譯階段可以被處理的異常。 Checked異常和Runtime異常的區(qū)別和聯(lián)系 Checked異常都是可以被處理的異常,在程...
摘要:對(duì)異常的處理方法是打印異常的跟蹤棧信息并終止程序運(yùn)行。應(yīng)盡量對(duì)異常進(jìn)行適當(dāng)?shù)奶幚?,而不是?jiǎn)單的將異常跟蹤棧信息打印出來(lái)。 一、異常概述 開(kāi)發(fā)者都希望所有錯(cuò)誤都能在編譯階段被發(fā)現(xiàn),就是試圖在運(yùn)行程序之前排除所有錯(cuò)誤,但這是不現(xiàn)實(shí)的,余下問(wèn)題必須在運(yùn)行期間得到解決。 Java將異常分為兩種:CheckedException和RuntimeException。其中,CheckedExcept...
閱讀 3298·2021-11-15 11:37
閱讀 1119·2021-11-02 14:45
閱讀 3925·2021-09-04 16:48
閱讀 3606·2019-08-30 15:55
閱讀 783·2019-08-23 17:53
閱讀 1016·2019-08-23 17:03
閱讀 2060·2019-08-23 16:43
閱讀 2211·2019-08-23 16:22