成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

捕獲異常然后再拋出另一個(gè)異常的正確姿勢(shì)

RebeccaZhong / 975人閱讀

摘要:下面我們來(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, in 
    raise 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, in 
    div()
  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, in 
    div()
  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, in 
    foobar()
  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, in 
    div()
  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, in 
    div()
  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 
    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ě)法

上面介紹了在 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, in 
    foobar()
  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, in 
    foobar()
  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

相關(guān)文章

  • 處理JavaScript異常正確姿勢(shì)

    摘要:我們使用單元測(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...

    lushan 評(píng)論0 收藏0
  • 《Java編程思想》筆記12.通過(guò)異常處理錯(cuò)誤

    摘要:一旦異常被拋出,就表明錯(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 概念 異...

    Vultr 評(píng)論0 收藏0
  • 使用Java Exception機(jī)制正確姿勢(shì)

    摘要:如何良好的在代碼中設(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...

    Astrian 評(píng)論0 收藏0
  • Java異常簡(jiǎn)介

    摘要:而異??梢圆槐伙@式的處理都是的子類(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異常都是可以被處理的異常,在程...

    wangym 評(píng)論0 收藏0
  • Java中異常處理

    摘要:對(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...

    wemall 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<