日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

Python異常信息的不同展現方法總結_python

作者:愛摸魚的菜鳥程序員 ? 更新時間: 2022-12-23 編程語言

簡介

在日常開發中,我們的大部分時間都會花在閱讀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

我們還可以讓異常信息自動存入文件中,在之后調試代碼的時候查看:

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")

異常信息默認會存儲到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

我們還可以給提示信息的某一部分設置顏色:

# 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很有趣,但許多第三方庫已經實現這一功能了。與其自己造輪子,不如看看其他優秀的工具。

首先,我個人最喜歡的是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

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

使用最方便的庫是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]

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()

stackprinter庫

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

結論

本文我們學習了如何自定義Exception Hooks,但我更推薦使用第三方庫。你可以在本文介紹的第三方庫中任選一個喜歡的,用到項目中。需要注意的是使用自定義Exception Hooks可能會丟失某些關鍵信息,例如:本文中的某些例子中,輸出中缺少文件路徑,在遠程調試代碼這無疑很不方便,因此,需要謹慎使用。

原文鏈接:https://blog.csdn.net/weixin_56659172/article/details/127998909

欄目分類
最近更新