. Python中的异常栈跟踪
之前在做Java的时候,异常对象默认就包含stacktrace相关的信息,通过异常对象的相关方法printStackTrace()和getStackTrace()等方法就可以取到异常栈信息,能打印到log辅助调试或者做一些别的事情。但是到了Python,在2.x中,异常对象可以是任何对象,经常看到很多代码是直接raise一个字符串出来,因此就不能像Java那样方便的获取异常栈了,因为异常对象和异常栈是分开的。而多数Python语言的书籍上重点在于描述Python中如何构造异常对象和raise try except finally这些的使用,对调试程序起关键作用的stacktrace往往基本上不怎么涉及。
python中用于处理异常栈的模块是traceback模块,它提供了print_exception、format_exception等输出异常栈等常用的工具函数。
def func(a, b):
returna / b
if__name__ =='__main__':
importsys
importtraceback
try:
func(1,0)
exceptExceptionase:
print"print exc"
traceback.print_exc(file=sys.stdout)
输出结果:
print exc
Traceback (most recentcalllast):
File"./teststacktrace.py", line7,in
func(1,0)
File"./teststacktrace.py", line2,infunc
return a / b
其实traceback.print_exc()函数只是traceback.print_exception()函数的一个简写形式,而它们获取异常相关的数据都是通过sys.exc_info()函数得到的。
def func(a, b):
returna / b
if__name__ =='__main__':
importsys
importtraceback
try:
func(1,0)
exceptExceptionase:
print"print_exception()"
exc_type, exc_value, exc_tb = sys.exc_info()
print'the exc type is:', exc_type
print'the exc value is:', exc_value
print'the exc tb is:', exc_tb
traceback.print_exception(exc_type, exc_value, exc_tb)
输出结果:
print_exception()
the exc typeis:
the exc valueis:integerdivisionormodulobyzero
the exc tbis:
Traceback (most recentcalllast):
File"./teststacktrace.py", line7,in
func(1,0)
File"./teststacktrace.py", line2,infunc
return a / b
sys.exc_info()返回的值是一个元组,其中第一个元素,exc_type是异常的对象类型,exc_value是异常的值,exc_tb是一个traceback对象,对象中包含出错的行数、位置等数据。然后通过print_exception函数对这些异常数据进行整理输出。
traceback模块提供了extract_tb函数来更加详细的解释traceback对象所包含的数据:
def func(a, b):
returna / b
if__name__ =='__main__':
importsys
importtraceback
try:
func(1,0)
except:
_, _, exc_tb = sys.exc_info()
forfilename, linenum, funcname, sourceintraceback.extract_tb(exc_tb):
print"%-23s:%s '%s' in %s()"% (filename, linenum, source, funcname)
输出结果:
samchimac:tracebacktest samchi$ python ./teststacktrace.py ./teststacktrace.py :7'func(1,0)'in()./teststacktrace.py :2'returna / b'infunc()
2. 使用cgitb来简化异常调试
如果平时开发喜欢基于log的方式来调试,那么可能经常去做这样的事情,在log里面发现异常之后,因为信息不足,那么会再去额外加一些debug log来把相关变量的值输出。调试完毕之后再把这些debug log去掉。其实没必要这么麻烦,Python库中提供了cgitb模块来帮助做这些事情,它能够输出异常上下文所有相关变量的信息,不必每次自己再去手动加debug log。
cgitb的使用简单的不能想象:
def func(a, b):
returna / b
if__name__ =='__main__':
importcgitb
cgitb.enable(format='text')
importsys
importtraceback
func(1,0)