曹逸君 Blog

11月 18, 2014

Python pdb 调试 自动异常中断

Python pdb 调试 自动异常中断

我通常不愿意跑pydev或者pycharm这类庞大的IDE. 个人认为IDE提供的最有价值的功能是方便的调试. Python自带一个调试库pdb.

pdb常规用法

你可能已经在这样使用pdb

import pdb

def func_to_debug(*arg, **kwarg):
    """doc"""
    ...
    pdb.set_trace()
    #Suspicious code
    ...

在python解释器运行的时候pdb.set_trace()会将代码中断,然后在pdb的交互界面中可以使用pdb的 交互命令 进行 pdb中可以执行任意python代码,对已有对象进行的修改也会直接生效. 输出对象 pp obj.__dict__['some_property'] 查看源码 list or l 查看调用栈 where or w 转到上级调用(step out) up or u 转到下级调用(step in) down or d 退出pdb quit or q

注意因为列表(list)和列出源码的命令list冲突.所以使用列表需要用 __builtins__.list

但代码抛出异常时我们还需要加入pdb.set_trace() 然后再次运行代码去debug. 这种动作重复十几次之后你就会感到厌烦. 事实上是可以做到抛出异常时自动进入pdb的. 在上层调用try..except 来捕获异常并中断即可. 敲try..except 调好再去掉十几次之后你就会感到厌烦.于是我们做成一个装饰器(decorator).

扔出异常时自动中断

准备代码:

import pdb, traceback, sys

def debug(func):
    def wrap(*arg, **kwarg):
        try:
            return func(*arg, **kwarg)
        except:
            type, value, tb = sys.exc_info()
            traceback.print_exc()
            pdb.post_mortem(tb)
    return wrap

这里debug作为装饰器(decorator)使用.将目标函数进行try..except包裹,抛出异常时中断. 使用:

@debug
def func_to_debug(*arg, **kwarg):
    ...

这样抛出异常就直接进入到pdb中断.无需重新运行代码(set up). 添加/去除调试也更加方便.(注释掉@debug)

作为package方便引用

当把debug装饰器代码复制十几次之后,你会感到厌烦. 于是我们在python库目录(Linux: /usr/local/lib/python2.7/dist-packages/)里新建目录debug

把debug脚本放进去debug.py

再在里面建立一个空的__init__.py 文件来告诉python这是个package.

最后再chown -R改变整个目录的所有者避免权限问题.

更改 /usr/local/lib/python2.7/dist-packages/ 需要root权限

然后在你的项目里就可以方便的引用debug装饰器了. from debug.debug import debug

其他信息

注意当你发布的时候他人的机器很可能没有debug这个package. 要么去除debug代码.要么一起打包. 用于release的工具: mr.developer

其他pdb替代品.(第三方库,需要安装)

  • ipdb (pip install ipdb) - like ipython (autocomplete, colors etc).
  • pudb (pip install pudb) - curses based (gui-like), good at browsing sourcecode.
  • pdb++ (pip install pdbpp) - autocomplete, colors, extra commands etc.

更多调试工具 图形化分析工具

Written with StackEdit.