亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

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

RebeccaZhong / 1044人閱讀

摘要:下面我們來看一下效果下次需要捕獲一個(gè)異常然后再拋出另一個(gè)異常的時(shí)候大家可以試試本文的方法。

一般實(shí)現(xiàn)捕獲異常然后再拋出另一個(gè)異常的方法類似下面這樣:

def div():
    2 / 0

try:
    div()
except ZeroDivisionError as e:
    raise ValueError(e)

不知道大家有沒有注意到這樣拋出異常的方式有一個(gè)很嚴(yá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

這樣的話非常不利于查找問題: 比如上面的例子中實(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 信息 (通過 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: 異常類實(shí)例/異常類

value: 初始化異常類的參數(shù)值/異常類實(shí)例(使用這個(gè)實(shí)例作為 raise 的異常實(shí)例)/元組/None

traceback: traceback 對(duì)象/None

下面我們來看看上面的方法是否可以應(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è)問題呢?

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 的寫法

上面介紹了在 Python 2 和 Python 3 下的不同解決辦法,那么如何寫一個(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è)異常類的實(shí)例。 上面 else 中之所以用 exec 去定義 reraise 函數(shù)是因?yàn)?raise tp, value, tb 在 Python 3 下會(huì)報(bào)語法錯(cuò)誤,所以用 exec 來 繞過 Python 3 下的語法錯(cuò)誤檢查。

下面我們來看一下效果: :

$ 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://www.ezyhdfw.cn/yun/38180.html

相關(guān)文章

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

    摘要:我們使用單元測(cè)試來驗(yàn)證一下我們使用了配合做單元測(cè)試。我們編寫相應(yīng)的單元測(cè)試你會(huì)發(fā)現(xiàn),如果出現(xiàn)異常,只是簡(jiǎn)單的返回。但是在上面異常拋出的時(shí)候,解釋器已經(jīng)不在中了,因此無法被捕獲。 譯者按: 錯(cuò)誤是無法避免的,妥善處理它才是最重要的! 原文: A Guide to Proper Error Handling in JavaScript Related Topics: 譯者: Funde...

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

    摘要:一旦異常被拋出,就表明錯(cuò)誤已無法挽回,也不能回來繼續(xù)執(zhí)行。這種在編譯時(shí)被強(qiáng)制檢查的異常稱為被檢查的異常。通過獲取原始異常。構(gòu)造器對(duì)于在構(gòu)造階段可能會(huì)拋出異常,并要求清理的類,最安全的做法是使用嵌套的子句。 點(diǎn)擊進(jìn)入我的博客 Java異常處理的目的在于通過使用少于目前數(shù)量的代碼來簡(jiǎn)化大型、可靠的程序的生成,并且通過這種方式可以使你更自信:你的應(yīng)用中沒有未處理的錯(cuò)誤。 12.1 概念 異...

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

    摘要:如何良好的在代碼中設(shè)計(jì)異常機(jī)制本身設(shè)計(jì)的出發(fā)點(diǎn)是極好的,通過編譯器的強(qiáng)制捕獲,可以明確提醒調(diào)用者處理異常情況。但使用此種異常后,該會(huì)像病毒一樣,得不到處理后會(huì)污染大量代碼,同時(shí)也可能因?yàn)檎{(diào)用者的不當(dāng)處理,會(huì)失去異常信息。 1、異常是什么? 父類為Throwable,有Error和Exception兩個(gè)子類 Error為系統(tǒng)級(jí)別的異常(錯(cuò)誤) Exception下有眾多子類,常見的有Ru...

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

    摘要:而異??梢圆槐伙@式的處理都是的子類,繼承了的就是異常,其他的就是異常。常見異常類列舉幾個(gè)常見的運(yùn)行時(shí)異常數(shù)組越界異??罩羔槷惓n愞D(zhuǎn)換異常數(shù)字格式異常運(yùn)算異常。 Java異常 java異常分為兩大類,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)單的將異常跟蹤棧信息打印出來。 一、異常概述 開發(fā)者都希望所有錯(cuò)誤都能在編譯階段被發(fā)現(xiàn),就是試圖在運(yùn)行程序之前排除所有錯(cuò)誤,但這是不現(xiàn)實(shí)的,余下問題必須在運(yùn)行期間得到解決。 Java將異常分為兩種:CheckedException和RuntimeException。其中,CheckedExcept...

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

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

0條評(píng)論

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