如何在Python中保留異常裝飾器的堆疊跟蹤

華科雲商小雪發表於2024-02-05

異常裝飾器是一種透過裝飾器(Decorator)機制來捕獲和處理函式中異常的技術。當函式中發生異常時,裝飾器可以捕獲異常並進行處理,也可以記錄異常資訊或進行其他操作。堆疊跟蹤(Stack Trace)是指在發生異常時,系統會輸出一個包含異常資訊和函式呼叫鏈的資訊。對於經常使用python做爬蟲來說,這些知識點還是要必須要會的。

1、問題背景

在 Python 中,我們經常會使用裝飾器來對函式進行包裝,以便在函式呼叫前後執行一些額外的操作。當函式在裝飾器中丟擲異常時,預設情況下,堆疊跟蹤資訊將指向裝飾器函式,而不是實際引發異常的函式。這使得除錯和定位問題變得困難。

2、解決方案

為了保留異常裝飾器的堆疊跟蹤資訊,我們可以使用以下兩種方法:

  1. 使用 raise 語句的三引數形式

在 Python 2.x 中,我們可以使用 raise 語句的三引數形式來指定異常型別、異常例項和堆疊跟蹤資訊。例如:


class 
MyError(
Exception):

    pass

def try_except( fn):
    def wrapped( * args, ** kwargs):
        try:
            return fn( * args, ** kwargs)
        except Exception as e:
            et, ei, tb = sys. exc_info()
            raise MyError, MyError( e), tb
    return wrapped

def bottom():
    1 / 0

@try_except
def middle():
    bottom()

def top():
    middle()

>>> top()
Traceback ( most recent call last):
  File "<stdin>", line 1, in < module >
  File "tmp.py", line 24, in top
    middle()
  File "tmp.py", line 10, in wrapped
    return fn( * args, ** kwargs)
  File "tmp.py", line 21, in middle
    bottom()
  File "tmp.py", line 17, in bottom
    1 / 0
__main__. MyError: integer division or modulo by zero

在上面的例子中, try_except 裝飾器會捕獲函式 middle 中丟擲的異常,並使用 raise 語句的三引數形式重新丟擲異常。這樣,堆疊跟蹤資訊就會指向函式 bottom ,而不是函式 middle

  1. 使用 traceback 模組

在 Python 3 中,我們還可以使用 traceback 模組來獲取和操作堆疊跟蹤資訊。例如:


import 
sys

import traceback

class MyError( Exception):
    pass

def try_except( fn):
    def wrapped( * args, ** kwargs):
        try:
            return fn( * args, ** kwargs)
        except Exception as e:
            exc_type, exc_instance, exc_traceback = sys. exc_info()
            formatted_traceback = ''. join( traceback. format_tb(
                exc_traceback))
            message = '\n{0}\n{1}:\n{2}'. format(
                formatted_traceback,
                exc_type. __name__,
                exc_instance. message
           )
            raise MyError( message)
    return wrapped

def bottom():
    1 / 0

@try_except
def middle():
    bottom()

def top():
    middle()

>>> top()
Traceback ( most recent call last):
  File "<stdin>", line 1, in < module >
  File "tmp.py", line 24, in top
    middle()
  File "tmp.py", line 10, in wrapped
    return fn( * args, ** kwargs)
  File "tmp.py", line 21, in middle
    bottom()
  File "tmp.py", line 17, in bottom
    1 / 0
__main__. MyError:
Traceback ( most recent call last):
  File "tmp.py", line 17, in bottom
    1 / 0

ZeroDivisionError: division by zero

在上面的例子中, try_except 裝飾器會捕獲函式 middle 中丟擲的異常,並使用 traceback 模組獲取堆疊跟蹤資訊。然後,裝飾器會使用 raise 語句重新丟擲異常,並將堆疊跟蹤資訊作為異常訊息的一部分。這樣,堆疊跟蹤資訊就會指向函式 bottom ,而不是函式 middle

上面就是我對於堆疊跟蹤的一些理解,如果有任何不懂的可以評論區留言討論,在實際應用中,異常處理方式可能因需求而異。有時候,簡單地列印堆疊跟蹤可能是一個除錯工具,而在生產環境中,你可能會希望記錄異常資訊並採取適當的措施,例如傳送警報或者回滾事務。


來自 “ ITPUB部落格 ” ,連結:https://blog.itpub.net/70034537/viewspace-3006307/,如需轉載,請註明出處,否則將追究法律責任。

相關文章