Python 调试工具 pudb 的使用指南

本文作者: 伯乐在线legendtkl 。未经作者许可,禁止转载!
欢迎加入伯乐在线 专栏作者

最近在调试python程序,对于这种动态语言,我之前的方法大多都是打tag,真是痛苦的要死。话说回来,debug是为了什么?debug可以看成是对我们的猜测的一种验证。如果我们能通过工具将需要的信息(变量、堆栈)都显示出来,调试就很有效率。下面就介绍一个python调试工具:pudb。

本文部分内容参考自Professor Norm Matloff的文章,我特此发了邮件给他征得了翻译的权限。

Professor Norm Matloff, that is very nice of you, and thanks.

pudb是全屏的基于控制台的可视化调试器。如果你还记得Turbo C的话,看到这个你应该会感到亲切的。Homepage

pudb

先概要看一下pudb的特性:

  • 源码语法高亮,栈、断点、变量可见并且一直动态更新。变量展示还有很多可以定制化的功能。
  • 基于键盘,简单高效。为什么说高效呢?因为它支持VI的鼠标移动。还支持PDB的某些命令
  • 支持查找源代码,可以使用m代用module browser查看载入的模块
  • 断点设置:鼠标移到某行代码,按b,然后可以在断点窗口编辑断点
  • PuDB看重异常处理,post-mortem模式使折回到crash的最后一步更简单

安装

Python

1
2
3
pip install pudb
or
easy_install pudb

使用

为了支持pudb,需要在代码中插入

Python

1
2
3
from pudb import set_trace; set_trace()
or
import pudb; pu.db

然后通过下面命令启动pudb

Python

1
pudb myscript.py

step by step

我们以下面这段二分程序binsearch.py为例子

Python

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import pudb; pu.db
 
def findinspt(x, xnew):
    n = len(x)
    lo = 0
    hi = n1
    while True:
        mid = (lo + hi) / 2
        if xnew > x[mid]:
            lo = mid + 1
        else:
            hi = mid
        if xnew == x[mid]:
            return mid
 
if __name__ == “__main__”:
    y = [5,12,13]
    print findinspt(y,3)
    print findinspt(y,8)
    print findinspt(y,12)
    print findinspt(y,30)

运行下面命令

Python

1
pudb binsearch.py

不出意外会得到下面的窗口,左半边是源代码,右边一次是变量窗口、程序调用栈、断点

先介绍几个简单命令,不需要记住,因为下面会多次提到

  • n: next,也就是执行一步
  • s: step into,进入函数内部
  • c: continue
  • b: break point,断点
  • !: python command line
  • ?: help

最重要的是记住?,需要的时候按”?”查询
我们按一下n会发现y=[5,12,13]这行代码高亮显示了,表示执行到了这行代码。

再按一下n,y=[5,12,13]这行代码就执行完了,仔细看会发现右上角的变量窗口出现了y:list,表示程序内存中有了变量y。后面的List是type。

要查看y的值,按s即可。但是如果这个时候你要是不小心按到了Enter,你会发现下面的界面。

对的,这就是有关变量的所有信息。你只需要将光标移动到你要查看的信息,比如 Show repr(),按’Enter’键,再移动向右方向键到ok上,再按Enter键,就可以查看相应的信息的。但是如果你查看了变量不存在的信息,就会出现下面的画面。

当光标停在函数上的时候可以选择n执行到下一行代码,或者s进入函数内部。正常如果有终端输出的时候,pudb会回到终端。但是我在mac上并没有回去,有待进一步验证。这个时候我们执行n的时候,如果函数有问题,会出现异常:[PROCESSING EXCEPTION – hit e to examine]。按e就会显示异常的具体信息。

下面就是进入函数进行调试了。先按q选择restart重启pudb,执行到上面异常的哪一行选择s进入函数内部。这个时候findinspet()函数内部的变量就会显示在右上角变量窗口中。按n单步调试一会,发现lo,hi都变成0了。说明出现问题了。

修改程序。

Python

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import pudb; pu.db
 
def findinspt(x, xnew):
    n = len(x)
    lo = 0
    hi = n1
    while True:
        mid = (lo + hi) / 2
        if xnew > x[mid]:
            lo = mid + 1
        else:
            hi = mid
        if xnew == x[mid]:
            return mid
        if lo == hi:
            return lo
 
if __name__ == “__main__”:
    y = [5,12,13]
    print findinspt(y,3)
    print findinspt(y,8)
    print findinspt(y,12)
    print findinspt(y,30)

重新启动pudb。光标到main,按c会得到如下界面。

这时候选择restart,然后按o就可以看到输出结果了。

结果对于3,8,12都是对的,30的插入位置不对。为了让debug效率更高,下面使用断点功能。使用向下方向键,光标移动到第13行,按b即在该行设置了断点,右下角的断点显示窗口可以看到。

但是我们只想debug当xnew等于30的时候的情况。先使用向右方向键,再使用向下方向键到断点显示窗口的断点上,按Enter。下图。在condition的右侧设置条件xnew==30,点击OK保存。

使用方向键切换到左侧源码部分,先按n单步执行到main主程序,然后按c,程序就执行到了断点位置处。从右侧可以看到xnew的值为30。

这个时候就可以根据我们需要来单步调试了。对于本文的程序,会发现需要对边界条件处理一下。程序改为下面即可。

Python

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import pudb; pu.db
 
def findinspt(x, xnew):
    n = len(x)
    lo = 0
    hi = n1
    while True:
        mid = (lo + hi) / 2
        if xnew > x[mid]:
            lo = mid + 1
        else:
            hi = mid
        if xnew == x[mid]:
            return mid
        if lo == hi:
            if xnew <= x[lo]:
                return lo
            else:
                return lo
 
if __name__ == “__main__”:
    y = [5,12,13]
    print findinspt(y,3)
    print findinspt(y,8)
    print findinspt(y,12)
    print findinspt(y,30)

到此,基本上涉及了Debug的一些主要情况。如果说最后的程序是一个产品,Debug就是产品出问题时候的用来解决问题的工具。使用工具的效率一定程度也决定了产品的生产效率。

打赏支持我写出更多好文章,谢谢!
打赏作者

打赏支持我写出更多好文章,谢谢!

任选一种支付方式

3
8 收藏

评论





关于作者:legendtkl


文艺的技术青年,理想主义博客:Don’t Panic | 新浪微博:@HIT_Achilles


个人主页 ·
我的文章

· 6 ·   

转载自演道,想查看更及时的互联网产品技术热点文章请点击http://go2live.cn