调试程序是工作中必不可少的一项重要技能,程序调试可以帮助我们了解程序的运行过程,定位程序Bug。然而,离开了 Pycharm 等 IDE 的图形化界面调试器,很多 Python 工程师便只会使用 print 打印变量中间值。但是,随着代码量的增加,逻辑的进一步复杂,使用 print 打印中间变量的方式,就会显得效率低下,很难快速定位到问题。
本节,为大家准备了 pdb 和 ipdb 两个 Python 调试器。具有 C 或 C++ 背景的读者,肯定了解过 gdb 啦,gdb 是由 GNU 开源组织发布的一个命令行程序调试工具。pdb 和 gdb 保持了一样的用法,如果您学习过 gdb ,那么几乎不用学习就可以直接使用 pdb。
一. 标准库提供的 pdb
常用 pdb 命令如下:
命令 | 缩写 | 解释 |
---|---|---|
break | b | 设置断点 |
continue | cont / c | 继续执行至下一个断点 |
next | n | 执行下一行,但不会进入子程序 |
step | s | 执行下一行,下一行是子程序时,将进入子程序执行 |
where | bt / w | 打印堆栈轨迹 |
enable | - | 启用禁用的断点 |
disable | - | 禁用启用的断点 |
pp / p | - | 打印变量或表达式 |
list | l | 打印源码 |
up | u | 移动到上一层堆栈 |
down | d | 移动到下一层堆栈 |
restart | run | 重新开始调试 |
args | a | 打印函数参数 |
clear | cl | 清除所有的断点 |
return | r | 执行到当前函数结束 |
下面,我们启动 Python 调试器,有以下 2 种方式:
通过命令行启动
通过命令行启动 Python 调试器,只需要在命令行参数指定使用 pdb 模块启动 Python 脚本即可:
python -m pdb xxx.py
这种方式适用于程序文件较短的情景,运行上述命令,将在 Python 源码的第一行启动 Python 调试器。
在代码中添加断点
另一种方法是在 Python 代码中调用 pdb 模块的 set_trace 方法设置一个端点。当程序执行至断点时,将会暂停执行并打开 pdb 调试器。
下面,我们以一段简短的程序为例,来实践上文介绍的 pdb 命令。代码如下:
from __future__ import print_function
import pdb
def num_sum(n):
s = 0
for i in range(n):
pdb.set_trace()
s += i
print('****** {} *****'.format(s))
if __name__ == '__main__':
num_sum(10)
我们在 for
循环内部的第一行使用 pdb.set_trace()
来设置了一个断点,当程序运行至改行时将暂停执行,并运行 Python 调试器:
使用
where
/ bt
/ w
命令来查看当前函数的调用堆栈:使用
list
命令可以打印源码:使用
pp
/ p
可以打印任意变量的当前取值:next
向下执行1行:w
命令告诉我们程序当前执行到 s += i
,执行 n
命令,程序向下执行一行至 print
语句,此时打印 p i,s
:第 0 次循环 i = 0,s = 0 + 0,如下所示:下面,我们使用命令
c
进入第二次循环,打印变量 p i, s
,i = 1
已经进入第二次循环,s
之所以还为 0 ,是因为程序目前停在断点处,尚未执行到 s += i
;继续 c
之后,我们会发现 s
才会变为 2:二. 开源的 ipdb
ipdb 之于 pdb,就像 ipython 之于 python,实现的功能相同,但 ipdb 具有语法高亮、tab 补全、更友好的堆栈信息等优势。
注:pdb 是 Python 的标准库,无需安装直接使用,ipdb 为第三方库,需要使用 pip 安装后使用。
pip3 install -i https://pypi.doubanio.com/simple ipdb
可以发现 ipdb 的呈现也更加清晰、美观: