Traceback包
简介
traceback 是 Python 标准库中的一个模块,它提供了一组用于提取、格式化和打印程序执行过程中的堆栈跟踪信息的工具。当程序发生异常且未被捕获时,Python 会自动生成一个堆栈跟踪,显示出错的位置和调用栈。这有助于开发者理解和调试程序中出现的问题。
主要功能
当程序发生异常时,traceback模块可以用来捕获和格式化相关的堆栈信息。这有助于开发者快速定位问题所在。格式化的堆栈信息通常包括以下内容:
- 文件名:显示出现异常的代码所在的文件。
- 行号:指示引发异常的具体代码行在文件中的位置。
- 函数名:显示出现异常的代码所在的函数或方法的名称。
- 代码行:提供引发异常的实际代码行的文本。
traceback模块提供了多种函数来格式化和打印堆栈信息,下面是一些常用的函数:
traceback.print_tb(tb, limit=None, file=None)
- 打印堆栈跟踪的摘要。tb是一个traceback对象,limit指定打印的堆栈帧数目,file指定输出的文件对象(默认是sys.stderr)。
traceback.print_exception(etype, value, tb, limit=None, file=None, chain=True)
- 打印异常信息和堆栈跟踪。etype是异常类型,value是异常实例,tb是traceback对象,limit和file的含义与print_tb相同,chain确定是否打印异常链
traceback.format_tb(tb, limit=None)
- 返回堆栈跟踪的格式化表示,是一个字符串列表,每个字符串代表堆栈中的一个层级
traceback.format_exception(etype, value, tb, limit=None, chain=True)
- 返回一个列表,其中包含异常信息和堆栈跟踪的格式化字符串
traceback.format_exc(limit=None, chain=True)
- 返回最近异常的堆栈跟踪的格式化字符串,是format_exception的简化形式。
使用场景
下面有一个多层嵌套的函数调用
def main():
raise Exception("This is a test")
def pass_func_01():
return main()
def pass_func_02():
return pass_func_01()
def pass_func_03():
return pass_func_02()
def open_func():
pass_func_03()
if __name__ == "__main__":
open_func()
>>>
Traceback (most recent call last):
File "study-test/traceback-test/Demo03.py", line 17, in <module>
open_func()
File "study-test/traceback-test/Demo03.py", line 14, in open_func
pass_func_03()
File "study-test/traceback-test/Demo03.py", line 11, in pass_func_03
return pass_func_02()
File "study-test/traceback-test/Demo03.py", line 8, in pass_func_02
return pass_func_01()
File "study-test/traceback-test/Demo03.py", line 5, in pass_func_01
return main()
File "study-test/traceback-test/Demo03.py", line 2, in main
raise Exception("This is a test")
Exception: This is a test
如果出现报错会导致返回的报错链路过长,不适合对用户展示,我们就可以基于traceback包实现对于报错的重写
import sys
import _testcapi
import traceback
def main():
raise Exception("This is a test")
def pass_func_01():
return main()
def pass_func_02():
return pass_func_01()
def pass_func_03():
return pass_func_02()
def open_func():
try:
pass_func_03()
except Exception as e:
exc_type, exc_value, exc_traceback = sys.exc_info() # 获取到traceback需要的异常信息
tb = traceback.extract_tb(exc_traceback)
filtered_tb = [frame for frame in tb if "pass_func" not in frame[2]] # frame[2]是函数名称
formatted_lines = traceback.format_list(filtered_tb)
formatted_lines += traceback.format_exception_only(exc_type, exc_value)
custom_traceback = ''.join(formatted_lines)
try:
raise exc_type('\n'+custom_traceback) from None
except:
tp, exc, tb = sys.exc_info()
_testcapi.set_exc_info(tp, exc, tb.tb_next)
del tp, exc, tb
raise
if __name__ == "__main__":
open_func()
>>>
Traceback (most recent call last):
File "study-test/traceback-test/Demo03.py", line 36, in <module>
open_func()
Exception:
File "study-test/traceback-test/Demo03.py", line 19, in open_func
pass_func_03()
File "study-test/traceback-test/Demo03.py", line 6, in main
raise Exception("This is a test")
Exception: This is a test
在上述代码片中对报错进行了筛选,去掉了中间链路的报错信息,同时使用了_testcapi
包实现了对报错函数的包裹,提供给开发者系统性的简化报错信息的方案。