如何调试Python程序(pdb使用手册)

调试程序对于开发人员是一项非常重要的技能,它使得我们能够查看程序的运行过程,帮助我们准确的定位程序中的错误。

然而,令人意外的是,无数的Python工程师居然不知道如何对Python代码进行单步调试,遇到问题的时候只能通过print函数打印变量中间值这种低效的方式。究其原因,还是因为这类Python工程师没有意识到Python的强大,仅仅用Python来解决一些很简单的事情,如果总是写非常短小的Python代码,可能确实不需要调试器。但是,如果代码量大,逻辑复杂以后,还是用print函数打印变量中间值的方式进行调试,不但效率低下难以快速定位问题,而且特别打击开发者的自信心。所以,希望各位读者一开始就走在正确的道路上。

只要稍微花点时间,学会了Python的调试器,在以后的工作中,就能够快速的定位各种疑难杂症。在这篇文章中,我们将介绍两个Python调试器,分别是Python标准库自带的pdb和开源的ipdb。

标准库的pdb

pdb是Python自带的一个库,为Python程序提供了一种交互式的源代码调试功能,包含了现代调试器应有的功能,包括设置断点、单步调试、查看源码、查看程序堆栈等。如果读者具有C或C++程序语言背景,则一定听说过gdb。gdb是一个由GNU开源组织发布的、UNIX/LINUX操作系统下的、基于命令行的、功能强大的程序调试工具。如果读者之前使用过gdb,那么,几乎不用学习就可以直接使用pdb。pdb和gdb保持了一样的用法,这样可以降低工程师的学习负担和Python调试的难度,pdb提供的部分调试命令见下表。

有两种不同的方法启动Python调试器,一种直接在命令行参数指定使用pdb模块启动Python文件,如下所示:

python -m pdb test_pdb.py 

另一种方法是在Python代码中,调用pdb模块的set_trace方法设置一个断点,当程序运行自此时,将会暂停执行并打开pdb调试器。

#/usr/bin/python
from __future__ import print_function
import pdb

def sum_nums(n):
    s=0
    for i in range(n):
        pdb.set_trace()
        s += i
        print(s)

if __name__ == '__main__':
    sum_nums(5)

两种方法并没有什么质的区别,选择使用哪一种方式主要取决于应用场景,如果程序文件较短,可以通过命令行参数的方式启动Python调试器;如果程序文件较大,则可以在需要调试的地方调用set_trace方法设置断点。无论哪一种方式,都会启动Python调试器,前者将在Python源码的第一行启动Python调试器,后者会在执行到pdb.set_trace()时启动调试器。

启动Python调试器以后,就可以使用前面的调试命令进行调试,例如,下面这段调试代码,我们先通过bt命令查看了当前函数的调用堆栈,然后使用list命令查看了我们的Python代码,之后使用p命令打印了变量当前的取值,最后使用n执行下一行Python代码。

lmx@host1:~/temp$ python test_pdb.py
> test_pdb.py(9)sum_nums()
-> s += i
(Pdb) bt
  test_pdb.py(13)<module>()
-> sum_nums(5)
> test_pdb.py(9)sum_nums()
-> s += i
(Pdb) list
  4
  5     def sum_nums(n):
  6         s=0
  7         for i in range(n):
  8             pdb.set_trace()
  9  ->         s += i
 10             print(s)
 11
 12     if __name__ == '__main__':
 13         sum_nums(5)
[EOF]
(Pdb) p s
0
(Pdb) p i
0
(Pdb) n
> test_pdb.py(10)sum_nums()
-> print(s)

开源的ipdb

ipdb是一个开源的Python调试器,它和pdb有相同的接口,但是,它相对于pdb,具有语法高亮、tab补全、更友好的堆栈信息等高级功能。ipdb之于pdb,就相当于IPython之于Python,虽然都是实现相同的功能,但是,在易用性方面做了很多的改进。如下所示:


需要注意的是,pdb是Python的标准库,不用安装就可以直接使用。而ipdb是一个第三方的库,因此,需要使用pip先安装,然后才能使用:

pip install ipdb

将我们前面的例子,改为使用ipdb进行调试以后,代码就变成了下面这样:

from __future__ import print_function
import ipdb

def sum_nums(n):
    s=0
    for i in range(n):
        ipdb.set_trace()
        s += i
        print(s)

if __name__ == '__main__':
    sum_nums(5)

除了使用pdb和ipdb以外,如果读者使用PyCharm进行编程,则可以使用PyCharm的图形界面进行调试。PyCharm的图形界面的使用和显示都更加友好,几乎是傻瓜式操作。为了节省篇幅,PyCharm的调试功能在这里就不再介绍。

欢迎加入MySQL+Python+大数据+NoSQL技术交流QQ群(群号:306706593)。