Python 调试工具 pdb
pdb(Python Debugger)是Python内置的调试模块,允许开发者在代码运行时设置断点、检查变量、逐步执行代码,是调试复杂程序的强大工具。
1. 启动pdb
pdb可以通过多种方式启动,以下是最常用的方法:
1.1 在命令行运行pdb
通过在命令行中运行Python脚本并添加-m pdb参数,可以直接启动pdb。例如:
# 示例代码:simple_calc.py
def add(a, b):
result = a + b
return result
x = 10
y = 5
z = add(x, y)
print(f"Result: {z}")
在终端运行:
python -m pdb simple_calc.py
运行后,pdb会暂停在代码的第一行,显示(Pdb)提示符,进入交互模式。
1.2 在代码中嵌入pdb
在代码中插入pdb.set_trace(),程序会在该位置暂停并进入pdb调试模式。例如:
# 示例代码:embedded_pdb.py
import pdb
def multiply(a, b):
result = a * b
pdb.set_trace() # 程序在这里暂停
return result
x = 3
y = 4
z = multiply(x, y)
print(f"Result: {z}")
运行后,程序会在pdb.set_trace()处暂停,进入交互模式。
2. pdb基本命令
进入pdb后,可以使用一系列命令控制程序执行。以下是常用命令:
- h(elp):显示所有命令或某个命令的帮助。例如,
h显示所有命令,h n显示next命令的帮助。 - n(ext):执行当前行代码,移动到下一行(不进入函数)。
- s(tep):执行当前行代码,若为函数调用,则进入函数内部。
- c(ontinue):继续执行直到遇到下一个断点或程序结束。
- q(uit):退出pdb。
- l(ist):显示当前代码的上下文(默认11行,当前行居中)。
- p:打印表达式的值。例如,
p x打印变量x的值。
示例代码:
# 示例代码:basic_commands.py
import pdb
def divide(a, b):
pdb.set_trace() # 暂停以进入pdb
result = a / b
return result
x = 10
y = 2
z = divide(x, y)
print(f"Result: {z}")
运行后,在(Pdb)提示符下:
- 输入
p x查看x的值(结果:10)。 - 输入
n执行到下一行。 - 输入
l查看当前代码上下文。
3. 设置和管理断点
断点允许开发者在特定代码行暂停执行。pdb提供以下断点相关命令:
- b(reak) [lineno | function]:设置断点。例如,
b 5在第5行设置断点,b divide在函数divide入口设置断点。 - cl(ear) [bpnumber]:清除断点。例如,
cl 1清除编号为1的断点。 - disable [bpnumber]:禁用断点,但保留断点信息。
- enable [bpnumber]:启用已禁用的断点。
- breakpoints:列出所有断点。
示例代码:
# 示例代码:breakpoints.py
import pdb
def calculate_sum(n):
total = 0
for i in range(n):
total += i
return total
pdb.set_trace()
n = 5
result = calculate_sum(n)
print(f"Sum: {result}")
运行后,在(Pdb)提示符下:
- 输入
b calculate_sum在函数calculate_sum入口设置断点。 - 输入
c运行到断点。 - 输入
breakpoints查看断点列表。
4. 逐步调试与变量检查
逐步调试是pdb的核心功能,结合变量检查可以快速定位问题。
4.1 逐步执行
- n(ext):执行当前行,停在下一行。
- s(tep):进入函数或执行当前行。
- r(eturn):执行到当前函数返回。
示例代码:
# 示例代码:step_debug.py
import pdb
def factorial(n):
if n == 0:
return 1
return n * factorial(n - 1)
pdb.set_trace()
result = factorial(3)
print(f"Factorial: {result}")
运行后,在(Pdb)提示符下:
- 输入
s进入factorial函数。 - 输入
n逐步执行,观察递归过程。 - 输入
p n检查变量n的值。
4.2 检查与修改变量
- p:打印变量值。
- !variable = value:修改变量值。例如,
!x = 100将变量x的值改为100。
示例代码:
# 示例代码:variable_check.py
import pdb
def process_data(data):
pdb.set_trace()
data.append(100)
return data
values = [1, 2, 3]
result = process_data(values)
print(f"Result: {result}")
运行后,在(Pdb)提示符下:
- 输入
p data查看data的值(结果:[1, 2, 3])。 - 输入
!data[0] = 99修改data的第一个元素。 - 输入
p data确认修改(结果:[99, 2, 3])。
5. 条件断点与异常调试
5.1 条件断点
通过b [lineno], condition设置条件断点,仅在条件为真时暂停。例如,b 5, i > 2在第5行当i > 2时暂停。
示例代码:
# 示例代码:conditional_break.py
import pdb
def sum_numbers(n):
total = 0
for i in range(n):
total += i
return total
pdb.set_trace()
result = sum_numbers(5)
print(f"Sum: {result}")
运行后,在(Pdb)提示符下:
- 输入
b 5, i > 2在第5行(循环内)设置条件断点。 - 输入
c运行,程序仅在i > 2时暂停。
5.2 调试异常
pdb可以在异常发生时自动进入调试模式。使用post_mortem模式捕获异常:
# 示例代码:exception_debug.py
import pdb
def divide_numbers(a, b):
result = a / b
return result
try:
result = divide_numbers(10, 0)
print(f"Result: {result}")
except ZeroDivisionError:
pdb.post_mortem()
运行后,程序因除零异常暂停,进入pdb,开发者可以检查调用栈和变量。
6. 高级功能
6.1 调用栈导航
- w(here):显示当前调用栈。
- u(p):移动到上层调用栈。
- d(own):移动到下层调用栈。
示例代码:
# 示例代码:call_stack.py
import pdb
def inner_func(x):
pdb.set_trace()
return x * 2
def outer_func(y):
result = inner_func(y)
return result
value = 5
result = outer_func(value)
print(f"Result: {result}")
运行后,在(Pdb)提示符下:
- 输入
w查看调用栈。 - 输入
u移动到outer_func。 - 输入
p y检查y的值。
6.2 交互式执行
使用interact命令进入Python交互模式,可以运行任意Python代码。
示例代码:
# 示例代码:interactive.py
import pdb
def compute_square(n):
pdb.set_trace()
return n * n
value = 4
result = compute_square(value)
print(f"Square: {result}")
运行后,在(Pdb)提示符下:
- 输入
interact进入Python交互模式。 - 输入
print(n * 3)计算并打印n * 3。