Python traceback的优雅处理

 刚接触Python的时候,简单的异常处理已经可以帮助我们解决大多数问题,但是随着逐渐地深入,我们会发现有很多情况下简单的异常处理已经无法解决问题了,如下代码,单纯的打印异常所能提供的信息会非常有限。

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()来获取的,先来看一个例子:

import sys   def func1():     raise NameError("--func1 exception--")   def main():     try:         func1()     except Exception as e:         exc_type, exc_value, exc_traceback_obj = sys.exc_info()         print "exc_type: %s" % exc_type         print "exc_value: %s" % exc_value         print "exc_traceback_obj: %s" % exc_traceback_obj   if __name__ == '__main__':     main() 

执行后输出如下:

exc_type: <type 'exceptions.NameError'> exc_value: --func1 exception-- exc_traceback_obj: <traceback object at 0x7faddf5d93b0> 

通过以上示例我们可以看出,sys.exc_info()获取了当前处理的exception的相关信息,并返回一个元组,元组的第一个数据是异常的类型(示例是NameError类型),第二个返回值是异常的value值,第三个就是我们要的traceback object.

有了traceback object我们就可以通过traceback module来打印和格式化traceback的相关信息,下面我们就来看下traceback module的相关函数。

traceback module

Python的traceback module提供一整套接口用于提取,格式化和打印Python程序的stack traces信息,下面我们通过例子来详细了解下这些接口:

print_tb

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 "<ipython-input-23-52bdf2c9489c>", line 11, in main     func1() File "<ipython-input-23-52bdf2c9489c>", line 6, in func1     raise NameError("--func1 exception--") 

这里我们可以发现打印的异常信息更加详细了,下面我们了解下print_tb的详细信息:

traceback.print_tb(tb[, limit[, file]]) 
  • tb: 这个就是traceback object, 是我们通过sys.exc_info获取到的
  • limit: 这个是限制stack trace层级的,如果不设或者为None,就会打印所有层级的stack trace
  • file: 这个是设置打印的输出流的,可以为文件,也可以是stdout之类的file-like object。如果不设或为None,则输出到sys.stderr。

print_exception

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 "<ipython-input-24-a68061acf52f>", line 13, in main     func2()   File "<ipython-input-24-a68061acf52f>", line 9, in func2     func1() NameError: --func1 exception-- 

看下定义:

traceback.print_exception(etype, value, tb[, limit[, file]]) 
  • 跟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()来帮助获取这三个参数了,也因此这个函数是我们的程序中最常用的,因为它足够简单

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

输出(由于limit=1,因此只有一个层级被打印出来):

Traceback (most recent call last):   File 

                    
                
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信