一、什么是pdb?
pdb(Python Debugger) 是 Python 标准库自带的命令行调试器。它允许你单步执行代码、设置断点、检查变量值、查看调用栈等,是排查复杂问题的利器。
import pdb
defdivide(a, b):
pdb.set_trace() # 程序会在此处暂停
result = a / b
return result
divide(10, 2)
二、为什么需要pdb?
适用场景:
三、启动pdb的方式
3.1 在代码中插入断点(最常用)
import pdb
defbuggy_function(x):
pdb.set_trace() # 程序在此处暂停
y = x * 2
z = y + 10
return z
buggy_function(5)
3.2 命令行启动(-m pdb)
# 运行脚本并进入调试模式
python -m pdb my_script.py
3.3 异常时自动进入(-i 选项)
# 程序抛出异常时自动进入pdb
python -i my_script.py
3.4 Python 3.7+ 使用 breakpoint()
# Python 3.7+ 推荐使用
breakpoint() # 等价于 pdb.set_trace()
四、pdb常用命令
4.1 基本控制命令
| | |
step | s | |
next | n | |
return | r | |
continue | c | |
until | unt | |
quit | q | |
4.2 查看信息命令
| | |
list | l | |
print <expr> | p | |
pp <expr> | pp | |
whatis <expr> | | |
args | a | |
where | w | |
up | u | |
down | d | |
4.3 断点管理命令
| | |
break <lineno> | b | |
break <func> | b | |
break <file>:<lineno> | b | |
break | b | |
condition <num> <expr> | cond | |
clear <num> | cl | |
disable <num> | disable | |
enable <num> | enable | |
tbreak | tb | |
4.4 其他命令
| | |
help | h | |
!<python> | ! | |
interact | | |
run | | |
alias | | |
! | ! | |
五、实战示例
5.1 基本调试流程
defcalculate_average(numbers):
total = sum(numbers)
count = len(numbers)
average = total / count
return average
defprocess_data(data):
result = []
for item in data:
if item > 0:
result.append(item)
return result
defmain():
data = [10, -5, 20, -3, 15]
filtered = process_data(data)
avg = calculate_average(filtered)
print(f"结果: {avg}")
if __name__ == "__main__":
import pdb; pdb.set_trace()
main()
调试会话示例:
> test.py(23)main()
-> main()
(Pdb) s # 单步进入
> test.py(15)main()
-> data = [10, -5, 20, -3, 15]
(Pdb) n # 执行下一行
> test.py(16)main()
-> filtered = process_data(data)
(Pdb) s # 进入process_data函数
> test.py(9)process_data()
-> result = []
(Pdb) n
> test.py(10)process_data()
-> for item in data:
(Pdb) p data # 打印data变量
[10, -5, 20, -3, 15]
(Pdb) b 11 # 在第11行设置断点
Breakpoint 1 at test.py:11
(Pdb) c # 继续执行
> test.py(11)process_data()
-> if item > 0:
(Pdb) p item # 打印当前item
10
(Pdb) n
> test.py(12)process_data()
-> result.append(item)
(Pdb) !result.append(item) # 手动执行语句
(Pdb) n
> test.py(10)process_data()
-> for item in data:
(Pdb) c # 继续执行到下一个断点
5.2 条件断点
deffind_first_duplicate(lst):
seen = set()
for i, item inenumerate(lst):
# 在第15行设置条件断点:当重复时暂停
if item in seen:
return item
seen.add(item)
returnNone
lst = [1, 2, 3, 4, 5, 3, 6, 7]
import pdb; pdb.set_trace()
result = find_first_duplicate(lst)
设置条件断点:
(Pdb) b 6, item == 3 # 当item等于3时在第6行暂停
Breakpoint 1 at test.py:6
(Pdb) c # 继续执行
> test.py(6)find_first_duplicate()
-> if item in seen:
(Pdb) p item # 打印变量值
3
(Pdb) pp locals() # 打印所有局部变量
5.3 递归函数调试
deffactorial(n):
if n <= 1:
return1
return n * factorial(n - 1)
import pdb; pdb.set_trace()
print(factorial(5))
调试递归:
> test.py(9)<module>()
-> print(factorial(5))
(Pdb) s # 单步进入
> test.py(2)factorial()
-> def factorial(n):
(Pdb) s
> test.py(3)factorial()
-> if n <= 1:
(Pdb) n
> test.py(6)factorial()
-> return n * factorial(n - 1)
(Pdb) p n
5
(Pdb) s # 进入下一层递归
> test.py(3)factorial()
-> if n <= 1:
(Pdb) w # 查看调用栈
test.py(10)factorial()
-> return n * factorial(n - 1)
test.py(10)factorial()
-> return n * factorial(n - 1)
test.py(10)factorial()
-> return n * factorial(n - 1)
test.py(10)factorial()
-> return n * factorial(n - 1)
test.py(10)factorial()
-> return n * factorial(n - 1)
> test.py(6)factorial()
-> return n * factorial(n - 1)
(Pdb) u # 向上移动栈帧
> test.py(10)factorial()
-> return n * factorial(n - 1)
(Pdb) p n # 查看该层的n值
4
六、高级技巧
6.1 调试装饰器
import pdb
from functools import wraps
defdebug_decorator(func):
@wraps(func)
defwrapper(*args, **kwargs):
print(f"调用 {func.__name__}")
# 可以直接在装饰器中添加断点
breakpoint()
return func(*args, **kwargs)
return wrapper
@debug_decorator
defcalculate(x, y):
return x + y
calculate(10, 20)
6.2 使用命令文件
# 创建 commands.pdb 文件
# break 15
# condition 1 item == 'error'
# continue
# 使用命令文件启动调试
python -m pdb -c commands.pdb my_script.py
6.3 别名创建
# 在pdb中创建别名
(Pdb) alias pv !print(f"{'='*20}\n{locals()}\n{'='*20}")
(Pdb) pv # 使用别名打印所有局部变量
6.4 远程调试
import pdb
import socket
import sys
classRemotePdb(pdb.Pdb):
def__init__(self, port=4444, host='localhost'):
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._socket.bind((host, port))
self._socket.listen(1)
print(f"等待连接 {host}:{port}")
client, addr = self._socket.accept()
sys.stdin = client.makefile('r')
sys.stdout = client.makefile('w')
pdb.Pdb.__init__(self, stdin=sys.stdin, stdout=sys.stdout)
defshutdown(self):
self._socket.close()
# 使用方法
defremote_debug():
RemotePdb().set_trace()
print("程序继续执行")
# 其他代码
七、常见问题及解决
7.1 在循环中调试
defprocess_multiple_items(items):
for i, item inenumerate(items):
# 设置条件断点,只在特定迭代暂停
import pdb; pdb.set_trace() if i == 5elseNone
process_item(item)
7.2 使用 breakpoint() 兼容不同环境
# 可以通过环境变量控制调试行为
import os
if os.environ.get('DEBUG'):
breakpoint() # 仅在调试模式下暂停
7.3 跳过模块代码
# 使用`skip`参数跳过特定模块
import pdb
pdb.set_trace(skip=['my_module.*'])
八、pdb vs 其他调试工具
使用ipdb(推荐替代)
pip install ipdb
import ipdb; ipdb.set_trace() # 支持Tab补全和语法高亮
九、pdb调试技巧总结
常用工作流:
- 1. 在可疑位置设置断点:
breakpoint() 或 pdb.set_trace() - 4. 单步执行:
n(不进入函数)或 s(进入函数) - 5. 设置条件断点:
b lineno, condition
常用快捷键:
十、总结
核心要点:
- • pdb 是 Python 标准库内置的命令行调试器。
- • 使用
breakpoint() 或 pdb.set_trace() 在代码中设置断点。 - • 支持单步执行、查看变量、设置条件断点、调用栈分析等功能。
- • 常用命令:
n(next), s(step), c(continue), p(print), b(break), w(where)。 - • 适用于复杂问题的交互式排查,是开发者的必备工具。
最佳实践:
- 1. 优先使用
breakpoint() 而非 pdb.set_trace() - 3. 结合
print 和 logging 形成完整调试策略
掌握 pdb 可以让你的调试效率大幅提升,尤其是在无法使用 IDE 或需要远程调试的场景中,它是不可或缺的工具。