今日记录一下一个非常好用的模块:traceback
# -*- coding:utf-8 -*-
def func1():
raise Exception("--func1 exception--")
def main():
try:
func1()
except Exception as e:
print(e)
if __name__ == '__main__':
main()
执行后输出如下:
--func1 exception--
通过示例,我们发现普通的打印异常只有很少量的信息(通常是异常的value值),这种情况下我们很难定位在哪块代码出的问题,以及如何出现这种异常。那么到底要如何打印更加详细的信息呢?下面我们就来一一介绍。
sys.exc_info和traceback object
Python程序的traceback
信息均来源于一个叫做traceback object
的对象,而这个traceback object
通常是通过函数sys.exc_info()
来获取的,先来看一个例子:
# -*- coding:utf-8 -*-
import sys
def func1():
raise NameError("--func1 exception--")
def main():
try:
func1()
except Exception as e:
print(e)
exc_type, exc_value, exc_traceback_obj = sys.exc_info()
print(f"exc_type: {exc_type}")
print(f"exc_value: {exc_value}")
print(f"exc_traceback_obj: {exc_traceback_obj}")
if __name__ == '__main__':
main()
执行输出后如下:
--func1 exception--
exc_type:
exc_value: --func1 exception--
exc_traceback_obj:
通过以上示例我们可以看出,sys.exc_info()
获取了当前处理的exception
的相关信息,并返回一个元组,元组的第一个数据是异常的类型(示例是NameErro
r类型),第二个返回值是异常的value
值,第三个就是我们要的traceback object
.
有了traceback object
我们就可以通过traceback module
来打印和格式化traceback
的相关信息,下面我们就来看下traceback module
的相关函数。
traceback module
Python的traceback module
提供一整套接口用于提取,格式化和打印Python程序的stack traces
信息,下面我们通过例子来详细了解下这些接口:
print_tb
# -*- coding:utf-8 -*-
import sys
import traceback
def func1():
raise NameError("--func1 exception--")
def main():
try:
func1()
except Exception as e:
exc_type, exc_value, exc_traceback_obj = sys.exc_info()
traceback.print_tb(exc_traceback_obj)
if __name__ == '__main__':
main()
输出结果:
File "test_python.py", line 13, in main
func1()
File "test_python.py", line 8, in func1
raise NameError("--func1 exception--")
这里我们可以发现打印的异常信息更加详细了,下面我们了解下print_tb
的详细信息:
def print_tb(tb, limit=None, file=None):
"""Print up to 'limit' stack trace entries from the traceback 'tb'.
If 'limit' is omitted or None, all entries are printed. If 'file'
is omitted or None, the output goes to sys.stderr; otherwise
'file' should be an open file or file-like object with a write()
method.
"""
-
tb
: 这个就是traceback object
, 是我们通过sys.exc_info
获取到的 -
limit
: 这个是限制stack trace
层级的,如果不设或者为None,就会打印所有层级的stack trace
-
file
: 这个是设置打印的输出流的,可以为文件,也可以是stdout
之类的file-like object
。如果不设或为None,则输出到sys.stderr
。
print_exception
# -*- coding:utf-8 -*-
import sys
import traceback
def func1():
raise NameError("--func1 exception--")
def func2():
func1()
def main():
try:
func2()
except Exception as e:
exc_type, exc_value, exc_traceback_obj = sys.exc_info()
traceback.print_exception(exc_type, exc_value, exc_traceback_obj, limit=2, file=sys.stdout)
if __name__ == '__main__':
main()
输出结果:
Traceback (most recent call last):
File "test_python.py", line 17, in main
func2()
File "test_python.py", line 12, in func2
func1()
NameError: --func1 exception--
看下print_exception
的源码:
def print_exception(etype, value, tb, limit=None, file=None, chain=True):
"""Print exception up to 'limit' stack trace entries from 'tb' to 'file'.
This differs from print_tb() in the following ways: (1) if
traceback is not None, it prints a header "Traceback (most recent
call last):"; (2) it prints the exception type and value after the
stack trace; (3) if type is SyntaxError and value has the
appropriate format, it prints the line where the syntax error
occurred with a caret on the next line indicating the approximate
position of the error.
"""
- 跟
print_tb
相比多了两个参数etype
和value
,分别是exception type
和exception value
,加上tb(traceback object)
,正好是sys.exc_info()
返回的三个值 - 另外,与
print_tb
相比,打印信息多了开头的"Traceback (most...)"信息以及最后一行的异常类型和value
信息 - 还有一个不同是当异常为
SyntaxError
时,会有"^"来指示语法错误的位置
print_exc
print_exc
是简化版的print_exception
, 由于exception type
, value
和traceback object
都可以通过sys.exc_info()
获取,因此print_exc()
就自动执行exc_info()
来帮助获取这三个参数了,也因此这个函数是我们的程序中最常用的,因为它足够简单
# -*- coding:utf-8 -*-
import sys
import traceback
def func1():
raise NameError("--func1 exception--")
def func2():
func1()
def main():
try:
func2()
except Exception as e:
traceback.print_exc(limit=1, file=sys.stdout)
if __name__ == '__main__':
main()
输出结果:
Traceback (most recent call last):
File "test_python.py", line 17, in main
func2()
NameError: --func1 exception--
(由于limit=1,因此只有一个层级被打印出来)
print_exc
的源码:
def print_exc(limit=None, file=None, chain=True):
"""Shorthand for 'print_exception(*sys.exc_info(), limit, file)'."""
print_exception(*sys.exc_info(), limit=limit, file=file, chain=chain)
- 函数内部直接调用了
peint_exception
format_exc
# -*- coding:utf-8 -*-
import logging
import sys
import traceback
logger = logging.getLogger("traceback_test")
def func1():
raise NameError("--func1 exception--")
def func2():
func1()
def main():
try:
func2()
except Exception as e:
logger.error(traceback.format_exc(limit=None))
if __name__ == '__main__':
main()
从这个例子可以看出有时候我们想得到的是一个字符串,比如我们想通过logger
将异常记录在log
里,这个时候就需要format_exc
了,这个也是最常用的一个函数,它跟print_exc
用法大致相同,只是不直接打印而是返回了字符串。
format_exc
的源码:
def format_exc(limit=None, chain=True):
"""Like print_exc() but return a string."""
return "".join(format_exception(*sys.exc_info(), limit=limit, chain=chain))
-
format_exc
参数不支持输出到文件或者标准输出 只会返回一个字符串
traceback module
中还有一些其它的函数,但因为并不常用,就不在展开来讲,感兴趣的同学可以看下参考链接中的文档。
推荐使用loguru
记录异常信息 这个库能够更简洁的方式记录一些栈信息
参考文章:
Python Traceback详解