Skip to main content

Python 代码调试

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