调试与问题排查
高效定位和解决程序问题
调试思维
调试流程
├── 1. 复现问题
├── 2. 定位范围
├── 3. 分析原因
├── 4. 验证假设
├── 5. 修复问题
└── 6. 验证修复
Print调试法
# 基础打印
def calculate(a, b):
print(f"输入: a={a}, b={b}") # 查看输入
result = a * b + 10
print(f"计算结果: {result}") # 查看中间值
return result
# 条件打印
DEBUG = True
def debug_print(*args, **kwargs):
if DEBUG:
print("[DEBUG]", *args, **kwargs)
debug_print("这条只在调试模式显示")
# 打印调用栈
import traceback
def problematic_function():
traceback.print_stack() # 打印当前调用栈
# 打印变量类型和值
def inspect_variable(name, value):
print(f"{name}: type={type(value).__name__}, value={value!r}")
inspect_variable("data", {"key": [1, 2, 3]})
# 输出: data: type=dict, value={'key': [1, 2, 3]}
Python调试器 (pdb)
import pdb
def complex_function(data):
result = []
for item in data:
pdb.set_trace() # 程序会在这里暂停
processed = item * 2
result.append(processed)
return result
# pdb常用命令
# n (next) - 执行下一行
# s (step) - 进入函数
# c (continue) - 继续执行
# p variable - 打印变量
# l (list) - 显示当前代码
# q (quit) - 退出调试
# b line_num - 设置断点
# w (where) - 显示调用栈
# 更好的调试器: ipdb
# pip install ipdb
import ipdb
ipdb.set_trace()
# 或使用breakpoint()(Python 3.7+)
def my_function():
x = 10
breakpoint() # 自动进入调试器
return x * 2
VS Code调试
// .vscode/launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Python: 当前文件",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal"
},
{
"name": "Python: Flask",
"type": "debugpy",
"request": "launch",
"module": "flask",
"env": {
"FLASK_APP": "app.py",
"FLASK_DEBUG": "1"
},
"args": ["run", "--no-debugger"]
}
]
}
VS Code调试快捷键
├── F5 - 开始/继续调试
├── F9 - 切换断点
├── F10 - 单步跳过
├── F11 - 单步进入
├── Shift+F11 - 单步跳出
└── Shift+F5 - 停止调试
日志调试
import logging
# 配置日志
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('app.log'),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
def process_order(order_id):
logger.info(f"开始处理订单: {order_id}")
try:
order = get_order(order_id)
logger.debug(f"订单详情: {order}")
if not order:
logger.warning(f"订单不存在: {order_id}")
return None
result = calculate_total(order)
logger.info(f"订单 {order_id} 处理完成, 总额: {result}")
return result
except Exception as e:
logger.error(f"处理订单失败: {order_id}", exc_info=True)
raise
# 日志级别
# DEBUG - 详细信息,诊断问题
# INFO - 确认程序按预期工作
# WARNING - 表示可能出现问题
# ERROR - 由于严重问题,功能无法执行
# CRITICAL - 严重错误,程序可能无法继续
常见错误类型
语法错误
# SyntaxError: 语法错误
# 检查括号、引号、缩进是否匹配
# 错误
if x == 1
print("hello")
# 正确
if x == 1:
print("hello")
类型错误
# TypeError: 类型不匹配
# 错误
"hello" + 123
# 正确
"hello" + str(123)
# 调试技巧:检查变量类型
print(type(variable))
索引错误
# IndexError: 索引越界
lst = [1, 2, 3]
# lst[3] # IndexError
# 安全访问
if len(lst) > 3:
print(lst[3])
# 或使用异常处理
try:
value = lst[3]
except IndexError:
value = None
键错误
# KeyError: 字典键不存在
data = {"name": "张三"}
# data["age"] # KeyError
# 安全方式1: get方法
age = data.get("age", 0)
# 安全方式2: 检查键
if "age" in data:
age = data["age"]
属性错误
# AttributeError: 对象没有该属性
# 检查属性是否存在
if hasattr(obj, "method"):
obj.method()
# 使用getattr提供默认值
value = getattr(obj, "attr", "default")
性能调试
import time
import cProfile
# 简单计时
start = time.time()
result = slow_function()
end = time.time()
print(f"耗时: {end - start:.4f}秒")
# 装饰器计时
def timer(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__} 耗时: {end - start:.4f}秒")
return result
return wrapper
@timer
def my_function():
# 执行操作
pass
# 性能分析
cProfile.run('my_function()')
# 或保存到文件
cProfile.run('my_function()', 'profile_result')
# 内存分析
# pip install memory_profiler
from memory_profiler import profile
@profile
def memory_heavy_function():
big_list = [i for i in range(1000000)]
return sum(big_list)
调试清单
## 问题排查清单
### 基础检查
- [ ] 错误信息完整阅读了吗?
- [ ] 最近改动了什么代码?
- [ ] 问题能稳定复现吗?
### 数据检查
- [ ] 输入数据是否正确?
- [ ] 数据类型是否匹配?
- [ ] 边界值是否处理?
### 环境检查
- [ ] 依赖版本是否正确?
- [ ] 配置是否正确?
- [ ] 环境变量是否设置?
### 逻辑检查
- [ ] 条件判断是否正确?
- [ ] 循环是否正确终止?
- [ ] 异常是否正确处理?
本章小结
- Print调试:简单快速的入门方法
- 调试器:pdb/IDE调试器深入排查
- 日志:生产环境问题追踪
- 系统方法:复现→定位→修复→验证
→ 继续阅读:45-高效学习方法