Python Debugger pdb with Examples

Debugger概述

在开发环境中,使用IDE集成的Debugger(调试工具)进行Debug,能帮助我们开发人员看到代码运行时的状态,对于排查疑难问题,很有帮助。一般来说,Debugger允许我们设置断点,让代码执行到断点时暂停,以便于我们查看断点附近的状态;然后以单步执行的方式,一次只执行一条语句,以便于我们观察状态的变化;也允许我们进入到调用函数内,跟踪函数内代码执行的状态。Debugger还提供更多的调试设置选项,快速地忽略其他代码的执行或从很深的调用堆栈中跳出来,让我们可以关注问题点。

一般来说,IDE的debugger是基于命令行的debugger的。直接使用命令行,一般有两种情况:

  1. 在不能使用IDE方式时,代替IDE进行debugger。比如,在集成测试环境中,服务器没有提供GUI用户界面,不能运行开发环境IDE。这时可以使用远程debugger,或者命令行方式的debugger。
  2. 脚本化调试过程。对于某些复杂的调试场景,基于命令行debugger编写调试脚本,提高调试效率。

本文介绍的是Python的命令行debugger工具包pdb。

如何进入Debugger

假设我们有一个脚本 example.py 需要调试,

python -m pdb example.py

这样会执行到脚本的第一行代码并停顿下来。

pdb 本质上是一个Python的模块。因此,可以用于编写调试脚本。

# python code.

import pdb
import example
pdb.run('example.fun()')

我们也可以把pdb 固定写到代码中。这一般写在我们认为系统发生严重异常的地方,如assertion失败的地方。

import pdb

#...

pdb.set_trace()

pdb 命令

进入到pdb环境中以后,就可以执行pdb的debugger命令。一般来说,一个debugger的命令主要包括设置断点,查看变量值等。pdb所支持的具体的命令名称可以参考本文的参考文档;另外需要提示的是,除了文档中所列的命令之外,Python语句也是可以使用的。这里不重复列出所有的命令,但举几个例子以说明用法。

给第三方库设置断点

假设我们的脚本为 example.py, 其中使用了第三方库 pyrad, 现在我们想在模块 pyrad/client.py 的130行加断点,其命令为

(Pdb) break pyrad/client:130

打印变量的值

假设我们要打印某个变量 var的值,这个变量是一个复杂的对象,我们需要一个辅助库util来查看某个属性的值.

(Pdb) import util
(Pdb) pp util.util_fun(var)

找到目前的位置

有时候,我们会忘记当前位置,可以通过命令where (w) 来查看

(Pdb)where

pdb 脚本

有时候为了重复执行某个调试过程,我们可以基于pdb编写一个简单的脚本。我们可以将pdb的命令按顺序一行一行写在一个文本文件中,也可以将它们嵌到Bash脚本中。

# The content of the commands
$ cat cmds.txt
break abc/def.py:120
run
p ret

$ cat cmds.txt | python -mpdb example.py

或者,

python -m pdb example.py <<-EOF
  break abc/def.py:120
  run
  p ret
EOF

此外, .pdbrc 里面也可以放pdb命令,它会在开始pdb时自动执行。由于.pdbrc是对当前用户或当前目录下所有的pdb命令都生效的,因此一般只在里面放一些通用的命令,比如alias等。

alias 特别有用之处,不是给pdb的命令取别名,而是给一段Python代码取个名字。这对于查看有有点复杂的对象的值特别有用。 比如,我们定义别名pi, 用于打印一个对象的实例变量的值,

$cat .pdbrc
alias pi for k in %1.__dict__.keys(): print "%1.",k,"=",%1.__dict__[k]

$cat cmds.txt
break 20
pi result

其他语言的Debugger

Java Debugger, jdb.

Linux C/C++ Debugger, gdb.

Node.js Debugger (Inspect), Inspector Protocol

Debugger和Logging的对比

好的代码,应该有足够的logging语句,用于记录日志,特别适合于集成测试环境和生产环境的故障诊断。logging有多种详细级别,其中的DEBUG级别最详尽,也是诊断代码问题的重要信息。INFO级别记录了代码的主要步骤,或所处理信息的关键(但不机密)的字段。WARNING和ERROR级别记录的是系统的问题,WARNING意味着潜在的问题,解决以后,系统会运行的更好;而ERROR意味着已经出错了,一般会记下详细的调用栈信息,以便于问题诊断。FATAL级别通常意味着系统已经无法运行。

Debugger 是直指Bug的开发工具和问题诊断工具;Logging则是运维阶段的程序运行日志,可以用于异常分析,还可以用于系统运行情况的分析与审计等多种用途。

参考资料

  1. https://docs.python.org/2/library/pdb.html
  2. https://www.ibm.com/developerworks/cn/linux/l-cn-pythondebugger/index.html