news 2026/6/14 19:59:56

Python代码调试技巧

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python代码调试技巧

Python代码调试技巧

一、调试的基本方法

1.1 print调试

最简单但有效的调试方法。

def calculate_total(items):
total = 0
for item in items:
print(f"处理项目: {item}") # 调试输出
total += item['price'] * item['quantity']
print(f"当前总计: {total}") # 调试输出
return total

# 改进:使用更详细的输出
def calculate_total(items):
total = 0
for i, item in enumerate(items):
print(f"[{i}] 项目: {item['name']}, 价格: {item['price']}, 数量: {item['quantity']}")
subtotal = item['price'] * item['quantity']
total += subtotal
print(f" 小计: {subtotal}, 累计: {total}")
return total

1.2 使用logging

比print更专业的方式。

import logging

logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

def process_data(data):
logger.debug(f"开始处理数据: {data}")
result = transform(data)
logger.debug(f"转换结果: {result}")
return result

二、使用pdb调试器

2.1 基本使用

import pdb

def buggy_function(x, y):
result = x + y
pdb.set_trace() # 设置断点
return result * 2

# 运行时会在断点处暂停

2.2 pdb常用命令

# l(ist) - 显示当前代码
# n(ext) - 执行下一行
# s(tep) - 进入函数
# c(ontinue) - 继续执行
# p variable - 打印变量
# pp variable - 美化打印
# w(here) - 显示调用栈
# u(p) - 上移一层栈
# d(own) - 下移一层栈
# b(reak) - 设置断点
# cl(ear) - 清除断点
# q(uit) - 退出调试

2.3 条件断点

import pdb

def process_items(items):
for i, item in enumerate(items):
if i == 5: # 只在第5个项目时断点
pdb.set_trace()
process(item)

2.4 使用breakpoint()

Python 3.7+推荐使用breakpoint()代替pdb.set_trace()。

def calculate(x, y):
result = x + y
breakpoint() # 更简洁
return result * 2

三、使用ipdb

ipdb是pdb的增强版,提供更好的用户体验。

# 安装
pip install ipdb

# 使用
import ipdb

def debug_function():
x = 10
ipdb.set_trace()
y = x * 2
return y

四、远程调试

4.1 使用pdb远程调试

import pdb
import sys

class RemotePdb(pdb.Pdb):
def __init__(self, host='127.0.0.1', port=4444):
import socket
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.bind((host, port))
self.sock.listen(1)
print(f"等待连接: {host}:{port}")
conn, addr = self.sock.accept()
print(f"已连接: {addr}")
pdb.Pdb.__init__(self, stdin=conn.makefile('r'), stdout=conn.makefile('w'))

# 使用
RemotePdb().set_trace()

# 连接: telnet localhost 4444

五、使用IDE调试器

5.1 VSCode调试配置

// .vscode/launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Python: 当前文件",
"type": "python",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal"
},
{
"name": "Python: 模块",
"type": "python",
"request": "launch",
"module": "mymodule",
"args": ["--debug"]
}
]
}

5.2 PyCharm调试

- 点击行号设置断点
- F8: 单步执行
- F7: 进入函数
- Shift+F8: 跳出函数
- F9: 继续执行
- Alt+F9: 运行到光标处

六、断言调试

6.1 使用assert

def divide(a, b):
assert b != 0, "除数不能为0"
assert isinstance(a, (int, float)), "a必须是数字"
assert isinstance(b, (int, float)), "b必须是数字"
return a / b

# 禁用断言(生产环境)
# python -O script.py

6.2 自定义断言函数

def debug_assert(condition, message="断言失败"):
if not condition:
import traceback
traceback.print_stack()
raise AssertionError(message)

七、日志调试

7.1 结构化日志

import logging
import json

class JsonFormatter(logging.Formatter):
def format(self, record):
log_data = {
'timestamp': self.formatTime(record),
'level': record.levelname,
'message': record.getMessage(),
'module': record.module,
'function': record.funcName,
'line': record.lineno
}
return json.dumps(log_data)

handler = logging.StreamHandler()
handler.setFormatter(JsonFormatter())
logger = logging.getLogger()
logger.addHandler(handler)

7.2 上下文日志

import logging
from contextvars import ContextVar

request_id = ContextVar('request_id', default=None)

class ContextFilter(logging.Filter):
def filter(self, record):
record.request_id = request_id.get()
return True

logger = logging.getLogger()
logger.addFilter(ContextFilter())

八、性能调试

8.1 使用cProfile

import cProfile
import pstats

def slow_function():
total = 0
for i in range(1000000):
total += i
return total

# 分析性能
cProfile.run('slow_function()', 'profile_stats')

# 查看结果
stats = pstats.Stats('profile_stats')
stats.sort_stats('cumulative')
stats.print_stats(10)

8.2 使用line_profiler

# 安装
pip install line_profiler

# 使用装饰器
@profile
def slow_function():
total = 0
for i in range(1000000):
total += i
return total

# 运行
# kernprof -l -v script.py

8.3 使用timeit

import timeit

# 测量代码执行时间
time = timeit.timeit('sum(range(100))', number=10000)
print(f"执行时间: {time:.4f}秒")

# 比较不同实现
time1 = timeit.timeit('[i for i in range(100)]', number=10000)
time2 = timeit.timeit('list(range(100))', number=10000)

九、内存调试

9.1 使用tracemalloc

import tracemalloc

# 开始跟踪
tracemalloc.start()

# 执行代码
data = [i for i in range(1000000)]

# 获取快照
snapshot = tracemalloc.take_snapshot()
top_stats = snapshot.statistics('lineno')

# 显示前10个内存占用
for stat in top_stats[:10]:
print(stat)

tracemalloc.stop()

9.2 使用memory_profiler

# 安装
pip install memory_profiler

from memory_profiler import profile

@profile
def memory_intensive():
a = [1] * (10 ** 6)
b = [2] * (2 * 10 ** 7)
del b
return a

# 运行
# python -m memory_profiler script.py

十、调试装饰器

10.1 函数调用跟踪

import functools

def trace(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"调用 {func.__name__}({args}, {kwargs})")
result = func(*args, **kwargs)
print(f"{func.__name__} 返回 {result}")
return result
return wrapper

@trace
def add(a, b):
return a + b

10.2 异常捕获装饰器

import functools
import traceback

def catch_exceptions(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
print(f"异常在 {func.__name__}: {e}")
traceback.print_exc()
raise
return wrapper

十一、调试技巧

11.1 二分查找bug

# 注释掉一半代码,确定bug在哪一半
# 重复这个过程直到找到问题代码

11.2 橡皮鸭调试法

# 向别人(或橡皮鸭)解释代码
# 在解释过程中往往能发现问题

11.3 最小化重现

# 创建最小的可重现示例
def minimal_example():
# 只包含重现bug所需的最少代码
pass

11.4 检查假设

# 不要假设任何事情
# 验证每个假设
assert isinstance(data, list), f"data应该是list,实际是{type(data)}"
assert len(data) > 0, "data不应该为空"

十二、常见bug模式

12.1 可变默认参数

# 错误
def append_to(element, to=[]):
to.append(element)
return to

# 正确
def append_to(element, to=None):
if to is None:
to = []
to.append(element)
return to

12.2 闭包中的变量

# 错误
functions = []
for i in range(5):
functions.append(lambda: i)

# 所有函数都返回4

# 正确
functions = []
for i in range(5):
functions.append(lambda x=i: x)

12.3 浅拷贝vs深拷贝

import copy

original = [[1, 2], [3, 4]]

# 浅拷贝
shallow = original.copy()
shallow[0][0] = 999
print(original) # [[999, 2], [3, 4]] - 被修改了!

# 深拷贝
deep = copy.deepcopy(original)
deep[0][0] = 999
print(original) # [[1, 2], [3, 4]] - 没有被修改

十三、调试工具集

13.1 icecream

# 安装
pip install icecream

from icecream import ic

def calculate(x, y):
ic(x, y) # 自动显示变量名和值
result = x + y
ic(result)
return result

13.2 pysnooper

# 安装
pip install pysnooper

import pysnooper

@pysnooper.snoop()
def complex_function(x):
y = x * 2
z = y + 10
return z

# 自动记录每一行的执行和变量变化

13.3 hunter

# 安装
pip install hunter

import hunter

# 跟踪所有函数调用
hunter.trace(module='mymodule')

十四、调试最佳实践

1. 重现bug
2. 理解预期行为
3. 隔离问题
4. 使用版本控制二分查找
5. 添加测试用例
6. 修复后验证
7. 记录解决方案
8. 清理调试代码

十五、调试检查清单

- [ ] 能稳定重现bug吗?
- [ ] 错误消息说了什么?
- [ ] 最近改了什么?
- [ ] 输入数据是什么?
- [ ] 预期输出是什么?
- [ ] 实际输出是什么?
- [ ] 有日志吗?
- [ ] 有测试吗?
- [ ] 其他人能重现吗?

十六、总结

调试是软件开发的重要技能。掌握多种调试工具和技巧,从简单的print到专业的调试器,从性能分析到内存跟踪,可以大大提高问题定位和解决的效率。记住,好的调试不仅是找到bug,更是理解代码的过程。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/14 19:59:03

C# 生成命令行程序 将hex格式烧录程序转换成bin烧录格式

1.程序using System; using System.Collections.Generic; using System.IO; using System.Linq;namespace Hex2Bin {class Program{static void Main(string[] args){if (args.Length < 2 || args.Length > 3){ShowHelp();return;}string inputFile args[0];string outp…

作者头像 李华
网站建设 2026/6/14 19:53:02

PPTist:零安装在线PPT制作工具的完整指南

PPTist&#xff1a;零安装在线PPT制作工具的完整指南 【免费下载链接】PPTist PowerPoint-ist&#xff08;/pauəpɔintist/&#xff09;, An online presentation application that replicates most of the commonly used features of MS PowerPoint, allowing for the editin…

作者头像 李华
网站建设 2026/6/14 19:51:57

从一道编程题看算法思维:如何用Java高效解决‘动物园栅栏’排队问题

从一道编程题看算法思维&#xff1a;如何用Java高效解决‘动物园栅栏’排队问题 当你在技术面试或算法竞赛中遇到看似简单的题目时&#xff0c;能否快速识别其中的关键约束条件并将其转化为高效的代码逻辑&#xff1f;"动物园栅栏"问题正是这样一个绝佳的教学案例&am…

作者头像 李华
网站建设 2026/6/14 19:49:59

大疆无人机固件自由下载:DankDroneDownloader完整使用指南

大疆无人机固件自由下载&#xff1a;DankDroneDownloader完整使用指南 【免费下载链接】DankDroneDownloader A Custom Firmware Download Tool for DJI Drones Written in C# 项目地址: https://gitcode.com/gh_mirrors/da/DankDroneDownloader 你是否曾因固件升级导致…

作者头像 李华
网站建设 2026/6/14 19:48:55

GPT-Image-2技术架构深度拆解:2026年图像生成模型全面解析

GPT-Image-2是OpenAI在2025年底推出的原生多模态图像生成模型&#xff0c;基于扩散Transformer&#xff08;DiT&#xff09;架构&#xff0c;深度集成于GPT-4o体系之中。它在文本渲染准确率&#xff08;约92%&#xff09;、空间推理能力和多轮编辑方面实现了显著提升&#xff0…

作者头像 李华
网站建设 2026/6/14 19:48:54

Python变量本质、命名规则与常量写法(破除新手认知误区)

博客摘要90%新手都误解了Python变量&#xff1a;变量不是装数据的盒子&#xff0c;只是贴在内存上的标签。本文从内存底层拆解变量赋值逻辑&#xff0c;区分硬性命名红线与PEP8规范&#xff0c;补齐Python无原生常量的替代写法&#xff0c;覆盖面试高频考点。一、变量底层本质&…

作者头像 李华