pdb 基本使用
前言
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行打断。
更多资料
- Using the Debugger in Python
- Python Library Reference for the Extended Python Debugger
- https://stackoverflow.com/questions/25275410/conditional-breakpoint-using-pdb
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 /: 搜索 ,/. 搜索下一个/上一个