Python调试从入门到精通:pdb、VS Code、远程调试、asyncio

Python调试从入门到精通:pdb、VS Code、远程调试、asyncio 强烈推荐收藏Python 调试从入门到精通pdb、VS Code、远程调试、asyncio——10年经验总结的调试方法论你还用print()调试吗每次加一行 print 等半分钟重启、print 太多眼花缭乱、上线前还要删光。本文用 pdb 交互式调试打底配上 VS Code 可视化断点、远程容器调试、异步代码专用技巧最后给一个「先猜后证」的调试心法——让你从「打日志找 Bug」进化到「读代码推 Bug」。一、pdbPython 自带的神器90% 的人只用过 10%1.1 基础命令速查# 在代码中插入断点defbuggy_function(x,y):importpdb;pdb.set_trace()# 程序跑到这里会暂停resultx/y# 想检查 x 和 y 的值returnresult# 或者 Python 3.7 的简洁写法defbuggy_function(x,y):breakpoint()# 等效于上面但更简洁resultx/yreturnresult进入 pdb 后的常用命令命令简写作用nextn执行下一行不进入函数steps进入函数内部continuec继续执行到下一个断点wherew显示当前调用栈listl显示当前位置的源码print(x)p x打印变量 x 的值pp vars(obj)pp美观打印对象属性quitq退出调试returnr执行到当前函数返回until 42u 42执行到第 42 行argsa显示当前函数的参数1.2 pdb 实战调试一个 API 调用importhttpxasyncdeffetch_user(user_id:int):从 API 获取用户信息——这个函数偶尔返回 None为什么breakpoint()# 断点 1检查入参asyncwithhttpx.AsyncClient()asclient:urlfhttps://api.example.com/users/{user_id}responseawaitclient.get(url,timeout5)breakpoint()# 断点 2检查响应状态# p response.status_code# p response.text[:200]ifresponse.status_code200:dataresponse.json()breakpoint()# 断点 3检查解析后的数据# pp data# p data.get(name)returndataelifresponse.status_code404:returnNoneelse:breakpoint()# 断点 4意外的状态码# p response.status_code# p response.textraiseException(fUnexpected status:{response.status_code})调试流程# 运行时(Pdb)n# 先走到 url 那行(Pdb)p user_id# 确认 user_id 正确(Pdb)c# 继续到下一个断点response 返回后(Pdb)p response.status_code# 502? 看看为什么(Pdb)p response.text[:200]# 打印响应内容(Pdb)w# 看看是谁调用了这个函数1.3 条件断点# 只在特定条件下才暂停foriinrange(1000):# 只当 i 998 时暂停ifi998:breakpoint()process(i)# 或者用 pdb 的命令行方式# python -m pdb script.py# (Pdb) break 15, i 9981.4 事后调试post-mortem# 程序崩溃后自动进入 pdb 查看崩溃现场python-m pdb-ccontinuescript.py# 或者在代码中importpdbimporttracebackimportsysdefmain():try:buggy_function()exceptException:# 崩溃时自动进入 pdb查看所有变量的值pdb.post_mortem(sys.exc_info()[2])二、VS Code 可视化调试2.1 配置文件.vscode/launch.json{version:0.2.0,configurations:[{name:Python: FastAPI,type:debugpy,request:launch,module:uvicorn,args:[src.main:app,--reload,--host,0.0.0.0,--port,8000],jinja:true,env:{PYTHONPATH:${workspaceFolder},LOG_LEVEL:debug},justMyCode:false},{name:Python: 当前文件,type:debugpy,request:launch,program:${file},console:integratedTerminal,justMyCode:false}]}2.2 VS Code 断点技巧技巧操作场景条件断点右键断点 → Edit Breakpoint → Expression只在i 998时暂停日志断点右键断点 → Logpoint不暂停只打印i{i}异常断点Debug 面板 → Breakpoints → Raised Exceptions任何异常都暂停函数断点Debug 面板 → → Function Breakpoint断在函数入口WatchDebug 面板 → Watch实时监控表达式值三、远程调试容器里的代码怎么打断点3.1 Docker 内的调试# Dockerfile FROM python:3.12-slim RUN pip install debugpy COPY . /app WORKDIR /app CMD [python, -m, debugpy, --listen, 0.0.0.0:5678, --wait-for-client, src/main.py].vscode/launch.json远程附加{name:Python: Remote Attach,type:debugpy,request:attach,connect:{host:localhost,port:5678},pathMappings:[{localRoot:${workspaceFolder},remoteRoot:/app}]}3.2 生产环境应急调试# 1. 在正在运行的容器中安装 debugpydockerexec-itapp_container pipinstalldebugpy# 2. 注入调试器不重启进程dockerexec-itapp_container python-c import debugpy debugpy.listen((0.0.0.0,5678))print(调试器已激活请在 VS Code 中附加) debugpy.wait_for_client() # 3. VS Code 远程附加 → 现在可以打断点了⚠️ 紧急情况使用。调试完立刻关闭debugpy监听端口。四、asyncio 异步代码调试4.1 为什么不加断点就跳过asyncdeffetch_data():dataawaitapi_call()# 加了断点程序不暂停returndata# 原因await 被事件循环接管了pdb 在异步上下文中有盲区4.2 asyncio 调试模式importasyncio# 开启 asyncio 调试模式asyncio.run(main(),debugTrue)# 或环境变量# PYTHONASYNCIODEBUG1 python main.py开启后能检测到协程未被await常见 Bug事件循环运行时间过长回调执行耗时异常4.3 异步代码的 pdb 实用技巧asyncdefbuggy_async_func():breakpoint()# (Pdb) 模式下查看异步状态# p asyncio.all_tasks() → 查看所有未完成任务# p asyncio.current_task() → 当前任务# p task.done() → 任务是否完成# p task.exception() → 任务是否有异常用asyncio.all_tasks()查看事件循环中所有未完成的任务——排查死锁和未 await 的协程用asyncio.get_running_loop().time()查看事件循环运行时长用task.exception()检查异步任务是否有未处理的异常五、调试心法从「试错」到「推理」5.1 调试三步法① 复现 → 找到最小可复现案例 ② 二分 → 逐步缩小问题范围不是逐行读是二分划分 ③ 假设 → 先猜最可能的原因再验证不要无目的地加 print5.2 先猜后证练习# 这个函数有什么 Bug先猜再看答案defprocess_orders(orders:list[dict])-dict:result{}fororderinorders:result.setdefault(order[status],0)result[order[status]]order[amount]returnresult# 输入[{status: paid, amount: 100}, {status: paid, amount: 50}]# 期望输出{paid: 150}# 实际输出{paid: 100}# 答案# setdefault 只在 key 不存在时设置默认值# 第二个 order 时 paid 已存在setdefault 不执行 → 累加正确但初始值没重置# 修复result[order[status]] result.get(order[status], 0) order[amount]5.3 二分定位法# 问题process_pipeline 返回的结果不对但 200 行代码不知道哪里出了问题defprocess_pipeline(data):# 二分法先注释掉后半段datastep1(data)datastep2(data)# data step3(data) # 先注释掉# data step4(data) # 先注释掉returndata# → step2 后返回正确 → 问题在 step3 或 step4# → 恢复 step3继续测试# → step3 后返回错误 → 问题在 step3# → 在 step3 中再二分六、调试工具扩展工具用途安装ipdbpdb 增强版语法高亮Tab补全pip install ipdbpudb终端可视调试器比 pdb 直观pip install pudbicecream替代 print自动打印变量名和值pip install icecreamloguru生产级日志一行配置pip install logurusnoop追踪每行代码的执行pip install snoopbirdseye图形化追踪函数执行pip install birdseye七、总结场景最佳工具一句话本地单文件pdb breakpoint()原生最快日常项目开发VS Code 断点可视化条件断点容器/远程debugpy 附加不改代码运行时注入异步代码asyncio debug 模式检测未 await生产排查loguru 结构化日志不是调试是事后分析快速查看变量icecreamic(x)比print(fx{x})好用 10 倍先猜后证二分定位不是逐行读是推测→验证→缩小print 不是不能用而是不应该是你唯一的调试工具。掌握 pdb 交互式调试 VS Code 条件断点 远程 debugpy 附加你的调试效率能从「猜谜」进化到「推理」。标签#Python #调试 #pdb #VSCode #asyncio #程序员必读