前言

pdb是Python的交互式debugger,在单线程应用的调试中非常方便。但是使用pdb需要熟记一些指令,这需要稍微多花一小时到两小时时间,但是一旦学会熟练使用它,之后便可以省下更多小时的debugging时间。本文使用一些例子来帮助读者熟悉常用pdb指令,避免了低效的直接背指令含义。

在脚本中打开一个控制台

import code

def spam():
    eggs = 123
    print('The begin of spam')
    code.interact(banner='', local=locals())
    print('The end of spam')
    print('The value of eggs %s' % eggs)

if __name__ == "__main__":
    spam()

这段脚本能够在脚本执行过程中打开一个shell,现在执行这段脚本并检查shell中的变量值:

# python debugging.py
The begin of spam
>>> eggs
123
>>> eggs = 456
>>>
now exiting InteractiveConsole...
The end of spam
The value of eggs 123

可以发现它并不能修改shell中的变量不会影响到脚本中的变量的值。同时该方法在不同stack,或者说不同行之间的跳转非常难。但是pdb帮助我们实现了这些功能。

使用pdb进行debug

import pdb

def spam():
    print('The begin of spam')
    print('The end of spam')

if __name__ == "__main__":
    pdb.set_trace()
    spam()

这里使用pdb.set_trace()在spam()函数前面打上一个断点,它意味着即将执行spam(),但是程序在这里停止,并进入pdb的shell进行调试。执行这段脚本来加深对它的理解:

# python3 debugging.py
> /Users/wangx/test/debugging.py(9)<module>()
-> spam()
(Pdb) w                 # Where shows the current line
> /Users/wangx/test/debugging.py(9)<module>()
-> spam()
(Pdb) source spam       # View the source of spam
  3  	def spam():
  4  	    print('The begin of spam')
  5  	    print('The end of spam')
(Pdb) b 5               # Add a breakpoint to line 5
Breakpoint 1 at /Users/wangx/test/debugging.py:5
(Pdb) c                 # Continue until the next breakpoint or exception
The begin of spam
> /Users/wangx/test/debugging.py(5)spam()
-> print('The end of spam')
(Pdb) w                 # Where again
  /Users/wangx/test/debugging.py(9)<module>()
-> spam()
> /Users/wangx/test/debugging.py(5)spam()
-> print('The end of spam')
(Pdb) ll                # List the lines of current function
  3  	def spam():
  4  	    print('The begin of spam')
  5 B->	    print('The end of spam')
(Pdb) b                 # Show thw breakpoints
Num Type         Disp Enb   Where
1   breakpoint   keep yes   at /Users/wangx/test/debugging.py:5
	breakpoint already hit 1 time
(Pdb) cl 1              # Clear breakpoint 1
Deleted breakpoint 1 at /Users/wangx/test/debugging.py:5
(Pdb) c                 # Continue again
The end of spam

Commands 命令

commands命令有点复杂, 但是用处也很大。它能让你在遇到一个指定的断点的时候执行命令。让我们用下面的例子来理解它的使用:

import pdb

def spam(eggs):
    print('eggs:', eggs)

if __name__ == "__main__":
    pdb.set_trace()
    for i in range(5):
        spam(i)

下面开始调试:

$ python3 spam.py
> /home/wangx/test/spam.py(10)<module>()
-> for i in range(5):
(Pdb) b spam
Breakpoint 1 at /home/wangx/test/spam.py:4
(Pdb) commands 1
(com) print('The value of eggs: %s' % eggs)
(com) end
(Pdb) c
The value of eggs: 0
> /home/wangx/test/spam.py(5)spam()
-> print('eggs:', eggs)
(Pdb) c
eggs: 0
The value of eggs: 1
> /home/wangx/test/spam.py(5)spam()
-> print('eggs:', eggs)
(Pdb) cl 1
Deleted breakpoint 1 at /home/wangx/test/spam.py:4
(Pdb) c
eggs: 1
eggs: 2
eggs: 3
eggs: 4

正如上面看到的一样,在断点后添加commands后,每次到该断点都会执行该指令。当移除断点后,该指令就不再执行了。

Conditional Commands

import pdb

for node_num in range(50):
  do_something(node_num)
ck@rolled ~]$ python -m pdb abc.py
> /home/dcadm/abc.py(1)<module>()
-> import pdb
(Pdb) l
  1  -> import pdb
  2
  3     for node_num in range(50) :
  4       foo = 2**node_num
[EOF]
(Pdb) b 4, node_num > 4
Breakpoint 1 at /home/dcadm/abc.py:4
(Pdb) c
> /home/dcadm/abc.py(4)<module>()
-> foo = 2**node_num
(Pdb) node_num 
5
(Pdb)

其中,b 4, node_num > 4定义了一个有条件的断点,只有在node_num大于4时候才会在第4行打断。

更多资料

PUDB 调试

pudb是一个使用TUI(Terminal User Interface)的python debugger,即它是使用终端显示图像界面的调试器。

安装

pip install pudb --user

下面是一个代码片段作为示例,其中import pudb; pu.db为断点处:

def binary_search(lst, value):
    lo, hi = 0, len(lst)-1
    while lo < hi:
        import pudb; pu.db
        mid = lo + (hi-lo)//2
        if lst[mid] < value:
            lo = mid + 1
        else:
            hi = mid
    if lst[lo] == value:
        return lo
    else:
        return -1

binary_search([2, 3, 3, 5], 4)

按键指令

Ctrl+p: 打开属性设置 n: next,也就是执行一步 s: step into,进入函数内部 f: finsh current function,执行到当前函数返回值的地方 c: continue,继续执行 b: break point,在光标所在行添加或消除断点 t: to cursor,运行到光标位置 !: 打开python命令行 ?: 打开帮助窗口 q: quit,退出PUDB /: 搜索 ,/. 搜索下一个/上一个