一、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):
return a / b
if __name__ == '__main__':
import sys
import traceback
try:
func(1, 0)
except Exception as e:
print "print exc"
traceback.print_exc(file=sys.stdout)

 输出结果:

print exc
Traceback (most recent call last):
File "./teststacktrace.py", line 7, in <module>
func(1, 0)
File "./teststacktrace.py", line 2, in func
return a / b

其实traceback.print_exc()函数只是traceback.print_exception()函数的一个简写形式,而它们获取异常相关的数据都是通过sys.exc_info()函数得到的。

def func(a, b):
return a / b
if __name__ == '__main__':
import sys
import traceback
try:
func(1, 0)
except Exception as e:
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 type is: <type 'exceptions.ZeroDivisionError'>
the exc value is: integer division or modulo by zero
the exc tb is: <traceback object at 0x104e7d4d0>
Traceback (most recent call last):
File "./teststacktrace.py", line 7, in <module>
func(1, 0)
File "./teststacktrace.py", line 2, in func
return a / b
ZeroDivisionError: integer division or modulo by zero

sys.exc_info()返回的值是一个元组,其中第一个元素,exc_type是异常的对象类型,exc_value是异常的值,exc_tb是一个traceback对象,对象中包含出错的行数、位置等数据。然后通过print_exception函数对这些异常数据进行整理输出。

traceback模块提供了extract_tb函数来更加详细的解释traceback对象所包含的数据:

def func(a, b):
return a / b
if __name__ == '__main__':
import sys
import traceback
try:
func(1, 0)
except:
_, _, exc_tb = sys.exc_info()
for filename, linenum, funcname, source in traceback.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 <module>()
./teststacktrace.py :2 'return a / b' in func()

二、使用cgitb来简化异常调试

如果平时开发喜欢基于log的方式来调试,那么可能经常去做这样的事情,在log里面发现异常之后,因为信息不足,那么会再去额外加一些debug log来把相关变量的值输出。调试完毕之后再把这些debug log去掉。其实没必要这么麻烦,Python库中提供了cgitb模块来帮助做这些事情,它能够输出异常上下文所有相关变量的信息,不必每次自己再去手动加debug log。

cgitb的使用简单的不能想象:

def func(a, b):
return a / b
if __name__ == '__main__':
import cgitb
cgitb.enable(format='text')
import sys
import traceback
func(1, 0)

运行之后就会得到详细的数据:

A problem occurred in a Python script.  Here is the sequence of
function calls leading up to the error, in the order they occurred. /Users/samchi/Documents/workspace/tracebacktest/teststacktrace.py in <module>()
4 import cgitb
5 cgitb.enable(format='text')
6 import sys
7 import traceback
8 func(1, 0)
func = <function func> /Users/samchi/Documents/workspace/tracebacktest/teststacktrace.py in func(a=1, b=0)
2 return a / b
3 if __name__ == '__main__':
4 import cgitb
5 cgitb.enable(format='text')
6 import sys
a = 1
b = 0

  完全不必再去log.debug("a=%d" % a)了,个人感觉cgitb在线上环境不适合使用,适合在开发的过程中进行调试,非常的方便。

也许你会问,cgitb为什么会这么屌?能获取这么详细的出错信息?其实它的工作原理同它的使用方式一样的简单,它只是覆盖了默认的sys.excepthook函数,sys.excepthook是一个默认的全局异常拦截器,可以尝试去自行对它修改:

def func(a, b):
return a / b
def my_exception_handler(exc_type, exc_value, exc_tb):
print "i caught the exception:", exc_type
while exc_tb:
print "the line no:", exc_tb.tb_lineno
print "the frame locals:", exc_tb.tb_frame.f_locals
exc_tb = exc_tb.tb_next if __name__ == '__main__':
import sys
sys.excepthook = my_exception_handler
import traceback
func(1, 0)

  输出结果:

i caught the exception: <type 'exceptions.ZeroDivisionError'>
the line no: 14
the frame locals: {'my_exception_handler': <function my_exception_handler at 0x100e04aa0>, '__builtins__': <module '__builtin__' (built-in)>, '__file__': './teststacktrace.py', 'traceback': <module 'traceback' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/traceback.pyc'>, '__package__': None, 'sys': <module 'sys' (built-in)>, 'func': <function func at 0x100e04320>, '__name__': '__main__', '__doc__': None}
the line no: 2
the frame locals: {'a': 1, 'b': 0}

  看到没有?没有什么神奇的东西,只是从stack frame对象中获取的相关变量的值。frame对象中还有很多神奇的属性,就不一一探索了。

三、使用logging模块来记录异常

在使用Java的时候,用log4j记录异常很简单,只要把Exception对象传递给log.error方法就可以了,但是在Python中就不行了,如果直接传递异常对象给log.error,那么只会在log里面出现一行异常对象的值。

在Python中正确的记录Log方式应该是这样的:

logging.exception(ex)
logging.error(ex, exc_info=1) # 指名输出栈踪迹, logging.exception的内部也是包了一层此做法
logging.critical(ex, exc_info=1) # 更加严重的错误级别

  

Python之traceback错误堆栈信息处理的更多相关文章

  1. 转 Python3 错误和异常/ Python学习之错误调试和测试

    ########sample 0 https://www.cnblogs.com/Simon-xm/p/4073028.html except: #捕获所有异常 except: <异常名> ...

  2. Python实用笔记——错误处理

    让我们用一个例子来看看try的机制: try: print('try...') r = 10 / 0 print('result:', r) except ZeroDivisionError as e ...

  3. Python常见的错误汇总

    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 错误: [错误分析]第二个参数必须为类,否则会报TypeError,所以正确的应 ...

  4. Python学习_07_错误、异常

    地毯式地过语法终于快要结束了... Python中的常见异常 1.NameError:尝试访问一个未初始化的变量 2. ZeroDivisionError:除数为0 3. SyntaxError:Py ...

  5. python基础之错误、调试(异常处理)

    在程序运行过程中,总会遇到各种各样的错误. 有的错误是程序编写有问题造成的,比如本来应该输出整数结果输出了字符串,这种错误我们通常称之为bug,bug是必须修复的. 有的错误是用户输入造成的,比如让用 ...

  6. python常见的错误提示处理

    python常见的错误有 NameError变量名错误 IndentationError代码缩进错误 AttributeError对象属性错误 TypeError类型错误 IOError输入输出错误 ...

  7. Sublime Text 2下搭建Python环境常见错误

    Sublime Text 2下搭建Python环境时,最容易出的错误就是Python环境配置错误,导致build(Ctrl+B)后没有任何反应. 关于Python编程环境的配置,网上很容易搜索到.先默 ...

  8. Python:常见错误集锦(持续更新ing)

    初学Python,很容易与各种错误不断的遭遇.通过集锦,可以快速的找到错误的原因和解决方法. 1.IndentationError:expected an indented block 说明此处需要缩 ...

  9. /usr/bin/python^M: 解释器错误: 没有那个文件或目录

    遇见问题 因为linux在虚拟机中,所以就在本地敲python代码,敲完后再拿到虚拟机去执行,再输入./filename.py时,就遇到这样的一个问题: bash: ./filename.py: /u ...

随机推荐

  1. 学习 TList 类的实现[7]

    总结目前 TMyList 已具备的功能(3 个方法.3 个属性): Add: 添加; Delete: 删除; Clear: 清空;Count: 元素总数;Capacity: 已存在的所有元素位置数;L ...

  2. MathType中输入破折号的教程

    MathType公式编辑器中的包含的各种数学符号与模板已经足够我们在编辑公式时使用了,但是除此之外,MathType还有一些符号并不是数学专有的符号,但是在数学中也偶尔会用到,比如破折号.MathTy ...

  3. ios 获取手机相关的信息

    获取手机信息      应用程序的名称和版本号等信息都保存在mainBundle的一个字典中,用下面代码可以取出来 //获取版本号 NSDictionary *infoDict = [[NSBundl ...

  4. PHP-002

    PHP URL重写 怎样在IIS环境下配置Rewrite规则_百度经验 http://jingyan.baidu.com/article/c33e3f485a7c74ea15cbb50e.html W ...

  5. php 实现 java com.sun.org.apache.xml.internal.security.utils.Base64 Byte数组加密

    <?php function java_base64_encode($arr){ $str = ''; foreach ($arr as $key => $value) { $str .= ...

  6. 常用hive的CLI命令

    1.show tables  --查看所有表 2.desc tabname --查看表信息 3.dfs -ls 目录  查看hdfs上面的文件  dfs -lsr /user  递归显示目录/user ...

  7. unity动态加载(翻译) .

    AssetBundles are files which you can export from Unity to contain assets of your choice. These files ...

  8. C/C++中的变量和静态变量

    static有两种用法:一是面向过程程序设计语言中的static,用于普通变量和函数,不涉及类:二是面向对象程序设计中的static,主要涉及static在类中的作用. 面向过程设计中的static ...

  9. node中的对象

    1. class的概念 定义一个class,属性都是private,方法都是public. Hello.js: 使用class index.js: 2. 单例类 使用exports而不是module. ...

  10. 【BZOJ2217】[Poi2011]Lollipop 乱搞

    [BZOJ2217][Poi2011]Lollipop Description 有一个长度为n的序列a1,a2,...,an.其中ai要么是1("W"),要么是2("T& ...