首頁  >  文章  >  後端開發  >  漲知識! Python 的異常訊息還能這樣展現

漲知識! Python 的異常訊息還能這樣展現

王林
王林轉載
2023-04-11 16:40:031761瀏覽

漲知識! Python 的異常訊息還能這樣展現

簡介

在日常開發中,我們大部分的時間都會花在閱讀traceback模組資訊以及偵錯程式碼上。本文我們將改進traceback模組,讓其中的提示資訊更簡潔、更精確。

基於此目的,我們將會自訂Exception Hooks(異常處理鉤子),用來移除traceback中的冗餘訊息,只留下解決報錯所需的內容。此外,我也會介紹一些好用的第三方函式庫,你可以直接使用其中的Exception Hooks,來簡化traceback模組。

Exception Hooks

假如程式的例外資訊沒有被try/catch捕獲到,python解釋器就會呼叫sys.excepthook()函數,它會接收3個參數,分別是:type, value, traceback。這個函數也被稱為Exception Hook,會輸出程式的異常資訊。

我們來看看下面這個範例:

import sys
def exception_hook(exc_type, exc_value, tb):
 print('Traceback:')
 filename = tb.tb_frame.f_code.co_filename
 name = tb.tb_frame.f_code.co_name
 line_no = tb.tb_lineno
 print(f"File {filename} line {line_no}, in {name}")
 # Exception type 和 value
 print(f"{exc_type.__name__}, Message: {exc_value}")
sys.excepthook = exception_hook

在這個範例中,我們可以從traceback (tb)物件中取得到異常訊息出現的位置,位置資訊包含:檔案名稱(f_code.co_filename),函數/模組名稱(f_code.co_name), 和行數(tb_lineno)。此外,我們可以使用exc_type和exc_value變數來取得異常資訊的內容。

當我們呼叫一個會產生錯誤的函數時,exception_hook會輸出如下內容:

def do_stuff():
 # 写一段会产生异常的代码
 raise ValueError("Some error message")
do_stuff()
# Traceback:
# File /home/some/path/exception_hooks.py line 22, in <module>
# ValueError, Message: Some error message

上述例子提供了一部分異常信息,但要想獲取調試代碼所需的全部訊息,並知道異常出現的時間及位置,我們還需要深入研究下traceback物件:

def exception_hook(exc_type, exc_value, tb):
 local_vars = {}
 while tb:
 filename = tb.tb_frame.f_code.co_filename
 name = tb.tb_frame.f_code.co_name
 line_no = tb.tb_lineno
 print(f"File {filename} line {line_no}, in {name}")
 local_vars = tb.tb_frame.f_locals
 tb = tb.tb_next
 print(f"Local variables in top frame: {local_vars}")
...
# File /home/some/path/exception_hooks.py line 41, in <module>
# File /home/some/path/exception_hooks.py line 7, in do_stuff
# Local variables in top frame: {'some_var': 'data'}

由上面的例子可以看出,traceback物件(tb)本質上是一個鍊錶- 儲存著所有出現的exceptions。因此可以使用tb_next對tb進行遍歷,並列印每一個異常的資訊。在此基礎上,也可以使用tb_frame.f_locals屬性將變數輸出到console中,這有助於偵錯程式碼。

使用traceback物件輸出例外資訊是可行的,但是比較麻煩,此外輸出的資訊可讀性較差。更方便的做法是使用traceback模組,該模組內建了許多提取異常資訊的輔助函數。

目前我們已經介紹了Exception Hooks的基礎知識,接下來我們可以自訂一個exception hooks,並加入一些實用的特性。

自訂Exception Hooks

  1. 我們也可以讓例外資訊自動存入檔案中,之後偵錯程式碼的時候查看:
LOG_FILE_PATH = "./some.log"
FILE = open(LOG_FILE_PATH, mode="w")
def exception_hook(exc_type, exc_value, tb):
 FILE.write("*** Exception: ***n")
 traceback.print_exc(file=FILE)
 FILE.write("n*** Traceback: ***n")
 traceback.print_tb(tb, file=FILE)
# *** Exception: ***
# NoneType: None
#
# *** Traceback: ***
# File "/home/some/path/exception_hooks.py", line 82, in <module>
# do_stuff()
# File "/home/some/path/exception_hooks.py", line 7, in do_stuff
# raise ValueError("Some error message")
  1. 異常訊息預設會儲存到stderr中,如果你想改變儲存位置,可以這樣做:
import logging
logging.basicConfig(
 level=logging.CRITICAL,
 format='[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s',
 datefmt='%H:%M:%S',
 stream=sys.stdout
)
def exception_hook(exc_type, exc_value, exc_traceback):
 logging.critical("Uncaught exception:", exc_info=(exc_type, exc_value, exc_traceback))
# [17:28:33] {/home/some/path/exception_hooks.py:117} CRITICAL - Uncaught exception:
# Traceback (most recent call last):
# File "/home/some/path/exception_hooks.py", line 122, in <module>
# do_stuff()
# File "/home/some/path/exception_hooks.py", line 7, in do_stuff
# raise ValueError("Some error message")
# ValueError: Some error message
  1. 我們也可以給提示訊息的某一部分設定顏色:
# pip install colorama
from colorama import init, Fore
init(autoreset=True)# Reset the color after every print
def exception_hook(exc_type, exc_value, tb):
 local_vars = {}
 while tb:
 filename = tb.tb_frame.f_code.co_filename
 name = tb.tb_frame.f_code.co_name
 line_no = tb.tb_lineno
 # Prepend desired color (e.g. RED) to line
 print(f"{Fore.RED}File {filename} line {line_no}, in {name}")
 local_vars = tb.tb_frame.f_locals
 tb = tb.tb_next
 print(f"{Fore.GREEN}Local variables in top frame: {local_vars}")

除了上面介紹的例子,你還可以輸出每一幀的局部變量,或是找到出現異常的行中所引用的變數。這些Exception Hooks已經很成熟了,比起自訂Exception hooks,我建議你閱讀下其他開發者的原始碼,學習下他們的設計想法。

  •  輸出每一幀的局部變數[1]
  •  找到出現異常的行中所引用的變數[2]

第三方函式庫中的Exception Hooks

自訂一個Exception Hook很有趣,但許多第三方函式庫已經實現這一功能了。與其自己造輪子,不如看看其他優秀的工具。

  1. 首先,我個人最喜歡的是Rich,可以直接用pip進行安裝,然後導入使用。如果你只想在一個例子中使用,可以這樣做:python -m rich.traceback
# https://rich.readthedocs.io/en/latest/traceback.html
# pip install rich
# python -m rich.traceback
from rich.traceback import install
install(show_locals=True)
do_stuff()# Raises ValueError

漲知識! Python 的異常訊息還能這樣展現

  1. better_exceptions也很受歡迎,我們需要先設定環境變數BETTER_EXCEPTIONS=1,再用pip安裝。另外,如果你的TERM變數不是xterm,還要把SUPPORTS_COLOR設定為True。
# https://github.com/Qix-/better-exceptions
# pip install better_exceptions
# export BETTER_EXCEPTIONS=1
import better_exceptions
better_exceptions.MAX_LENGTH = None
# 检查你的 TERM 变量是否被设置为 `xterm`, 如果没有执行以下操作
# See issue: https://github.com/Qix-/better-exceptions/issues/8
better_exceptions.SUPPORTS_COLOR = True
better_exceptions.hook()
do_stuff()# Raises ValueError

漲知識! Python 的異常訊息還能這樣展現

  1. 使用最方便的函式庫是pretty_errors,只需導入即可:
# https://github.com/onelivesleft/PrettyErrors/
# pip install pretty_errors
import pretty_errors
# 如果你对默认配置满意的话,则无需修改
pretty_errors.configure(
 filename_display= pretty_errors.FILENAME_EXTENDED,
 line_number_first = True,
 display_link= True,
 line_color= pretty_errors.RED + '> ' + pretty_errors.default_config.line_color,
 code_color= '' + pretty_errors.default_config.line_color,
 truncate_code = True,
 display_locals= True
)
do_stuff()

除了直接導入外,上面的程式碼也顯示了該函式庫的一些可選配置。更多的配置可以查看這裡:配置[3]

漲知識! Python 的異常訊息還能這樣展現

  1. #IPython的ultratb模組
# https://ipython.readthedocs.io/en/stable/api/generated/IPython.core.ultratb.html
# pip install ipython
import IPython.core.ultratb
# Also ColorTB, FormattedTB, ListTB, SyntaxTB
sys.excepthook = IPython.core.ultratb.VerboseTB(color_scheme='Linux')# Other colors: NoColor, LightBG, Neutral
do_stuff()

漲知識! Python 的異常訊息還能這樣展現

  1. stackprinter库
# https://github.com/cknd/stackprinter
# pip install stackprinter
import stackprinter
stackprinter.set_excepthook(style='darkbg2')
do_stuff()

漲知識! Python 的異常訊息還能這樣展現

结论

本文我们学习了如何自定义Exception Hooks,但我更推荐使用第三方库。你可以在本文介绍的第三方库中任选一个喜欢的,用到项目中。需要注意的是使用自定义Exception Hooks可能会丢失某些关键信息,例如:本文中的某些例子中,输出中缺少文件路径,在远程调试代码这无疑很不方便,因此,需要谨慎使用。

以上是漲知識! Python 的異常訊息還能這樣展現的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:51cto.com。如有侵權,請聯絡admin@php.cn刪除