Python调试推荐用breakpoint()(3.7+),兼容版用import pdb; pdb.set_trace();关键命令:n/s/c/p/l;注意断点位置、多线程及async限制。

怎么在代码里插入断点启动 pdb
直接在想暂停的位置写 import pdb; pdb.set_trace(),Python 运行到这行就会停住,进入交互式调试器。Python 3.7+ 可以用更简洁的 breakpoint(),它默认调用 pdb.set_trace(),且受 PYTHONBREAKPOINT 环境变量控制,方便临时禁用。
常见错误:把 pdb.set_trace() 放在函数定义内部但没调用该函数——断点根本不会触发;或者放在条件分支里却没走那条路径。
- 推荐优先用
breakpoint(),开发时清晰,上线前设PYTHONBREAKPOINT=0就能全局跳过 - 如果用的是旧版 Python 或需要兼容性,坚持写
import pdb; pdb.set_trace() - 别把断点插在循环体第一行还忘了加条件,否则一跑就卡死
常用 pdb 命令有哪些必须记住
进入 pdb 后不是只能按回车。最关键的几个命令其实就五个:n(next,单步执行当前行)、s(step,进入函数内部)、c(continue,继续运行到下一个断点)、p (print 表达式值)、l(list,显示当前附近源码)。
容易踩的坑是混淆 n 和 s:比如当前行是 result = some_func(x),用 n 会直接执行完这个函数并停在下一行;用 s 才会跳进 some_func 的第一行。调试逻辑错误时,错用 n 可能直接跳过你想查的函数体。
-
pp比p更适合看复杂结构(如嵌套 dict),自动格式化输出 -
pp locals()快速查看当前所有局部变量 -
q是退出调试器(不是exit或quit,那些会报错)
为什么 run -m pdb script.py 有时不生效
用命令行启动调试时写 python -m pdb myscript.py,它会从头开始单步,但前提是脚本本身没有异常提前退出,也没有被其他模块的 sys.excepthook 拦截。更常见的问题是:脚本依赖命令行参数,而 -m pdb 不会自动透传参数。
正确做法是加 -- 分隔符,例如 python -m pdb myscript.py -- --input data.json -v,否则参数会被 pdb 解析掉,导致你的脚本收不到。
- 如果脚本里用了
argparse且没处理好sys.argv,-m pdb下可能抛SystemExit,看起来像“没反应” - 想跳过初始化部分、只调试某函数?不如直接在函数入口加
breakpoint(),比全程单步高效得多 -
-m pdb对 import 报错(如ModuleNotFoundError)无能为力——它还没跑到你代码那儿
调试多线程或异步代码时 pdb 会失灵吗
会。标准 pdb 是同步阻塞的,只挂起当前线程。如果你在子线程里打 breakpoint(),主线程可能已结束,终端看起来“卡住”或直接退出;async/await 场景下,breakpoint() 被调用时若不在 event loop 主线程,可能引发 RuntimeError: no running event loop。
这不是 pdb 的 bug,而是它没设计成线程安全或 async-aware。真实项目中,除非明确知道当前线程上下文,否则别在线程函数里硬塞 breakpoint()。
- 多线程调试建议改用
logging+ 关键变量打点,或用 IDE 的线程视图(如 PyCharm) - async 调试优先用
asyncio.debug=True配合日志,或改用支持协程的调试器(如debugpy) - 如果非要用 pdb,确保
breakpoint()在主线程、主协程中触发,且 event loop 正在运行
实际调试中最容易被忽略的,是断点位置和执行路径之间的偏差——你以为代码会走到那里,但它因为异常、短路逻辑或配置开关根本没进去。与其反复猜,不如先用 p sys._getframe().f_lineno 确认当前行号,再结合 l 看上下文。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










