这六个 Python 交互式调试技巧,能让你在命令行里快速定位问题.
写代码最怕什么。最怕程序跑着跑着突然崩了,或者结果完全不对。你用了一堆 print 打印日志,看得眼花缭乱。其实 Python 自带的一些调试技巧,能让你直接在命令行里跟代码做朋友。我整理了几个自己常用的方法,希望能帮你省点时间。
第一个技巧是用 python -i 跑脚本。平常我们直接 python script.py 执行完就退出了。改成 python -i script.py,脚本执行完毕或者报错后,终端会进入交互模式,不会退出。这时候你所有的变量、函数都还在内存里。你可以当场打印变量看看值,或者调用函数测试一下。比如你脚本里有个变量 a,最后结果跟你预期不一样,直接在交互窗口输入 a,回车就能看它到底是多少。不用再回去改代码加 print。
第二个技巧是手动触发 pdb。pdb 是 Python 自带的调试器,不用装任何包。你在代码里怀疑有问题的地方,插一行 import pdb; pdb.set_trace()。然后正常跑脚本,执行到这行时会自动停住。这时候你能看到当前所有局部变量。按 n 是执行下一行,按 s 是进入函数内部,按 c 是继续执行到下一个断点。大多数场景下这几个命令就够了。我以前调一个递归函数,每次递归结果都不对,用 pdb 跟了几步发现参数传错了。
第三个技巧是用 breakpoint() 替代 pdb.set_trace()。Python 3.7 之后有了内置的 breakpoint() 函数,效果跟 import pdb; pdb.set_trace() 一样,但写法更简单。而且你可以通过 PYTHONBREAKPOINT 环境变量来切换调试器。比如默认是 pdb,你装了 ipdb 后,设置 PYTHONBREAKPOINT=ipdb.set_trace,执行到 breakpoint() 就会进入更漂亮的 ipdb 界面。我一般用 ipdb,因为支持 tab 补全,还能语法高亮。
第四个技巧是在 pdb 里直接写 Python 代码。进入 pdb 后,你不仅能查看变量,还能改变量。比如你怀疑 if 条件判断错了,可以直接在调试器里输入 if a > 10: print('yes'),看结果对不对。甚至可以赋值,把某个变量改成你想要的值,然后继续跑。这比改代码重跑快太多。我有次调一个循环,跳出条件始终不满足,在 pdb 里直接把计数器改大,让循环提前结束,确认了问题出在条件上。
第五个技巧是事后调试 post-mortem 模式。有时候程序没有提前埋断点,但执行到某行直接抛异常崩溃了。你可以用 python -m pdb script.py 运行脚本。如果程序异常退出,pdb 会自动停在崩溃的那一行。这时候你能看到当时的局部变量和调用栈。比如你代码里有个除零错误,用 pdb 停住后,直接看变量就知道是谁变成了零。我经常用这招,因为很多 Bug 不是提前能预测到位置的。
第六个技巧是用 Python 的 logging 模块配合断点。调试不是只有断点。用 logging.debug() 在代码里写日志,然后设置日志级别为 DEBUG。运行脚本时,你可以通过环境变量控制日志输出,比如 export PYTHON_LOG_LEVEL=DEBUG。这样在线上环境可以通过调整日志级别看到更多信息,而不用修改代码。而且 logging 能显示文件名和行号,比 print 强很多。我维护老代码时,经常先加 logging 看下数据的流向,再决定断点放哪里。
这些技巧不需要装第三方工具,你电脑上只要有 Python 就能用。下次在命令行里遇到问题,别着急加 print,试试上面的方法。你会发现自己找 Bug 的速度快很多。