少写 print,早点下班:村长的 7 个 Python 调试小技巧
· 阅读需 4 分钟

新手调试三件套:加 print、跑一遍、删 print。加多了找不到在哪,删漏了上线被人看见。
其实 Python 自带一整套调试工具,不用装任何东西。今天村长把我在录视频、改学员代码时最常用的 7 个掏出来。
1. f-string 的等号:打印得带名字
user = "村长"
items = 3
price = 19.9
print(f"{user=} {items=} {price=} {items*price=:.2f}")
# -> user='村长' items=3 price=19.9 items*price=59.70
变量名自动带上,还能直接跟格式说明符。比 print("items:", items) 少改一半地方。
2. breakpoint():让程序停在案发现场
def calc(a, b):
result = a / b
breakpoint() # 程序在这里暂停,进入 pdb
return result
calc(10, 2)
暂停后常用的几个命令:
p 变量名 打印变量
l 查看当前代码上下文
n 执行下一行(不进函数)
s 进入函数内部
c 继续跑到结束
q 退出调试
村长划重点:Python 3.7 起
breakpoint()是内置函数,不用import pdb。设环境变量PYTHONBREAKPOINT=0可以一次性关掉所有断点,上线前不用逐个删。
3. pprint:嵌套结构别挤成一坨
from pprint import pprint
data = {
"课程": ["变量", "循环", "函数"],
"学员": {"小明": {"分数": 88, "进度": 0.6},
"小红": {"分数": 95, "进度": 0.9}},
}
pprint(data, sort_dicts=False, width=40)
字典套列表套字典,print 打出来是一行糊的,pprint 会自动换行缩进。
4. logging:分级别的、能留下的调试信息
import logging
logging.basicConfig(
level=logging.DEBUG,
format="%(asctime)s [%(levelname)s] %(message)s",
)
log = logging.getLogger(__name__)
log.debug("进入函数,参数 a=%s", 10)
log.info("处理完成 %d 条", 3)
log.warning("磁盘快满了")
print 只会一股脑输出;logging 能按级别开关、带时间和模块名、还能写进文件。调试期开 DEBUG,上线调成 INFO 就行,代码一行不用删。
5. traceback:拿到完整的错误现场
import traceback
try:
1 / 0
except ZeroDivisionError:
traceback.print_exc() # 打印完整堆栈到 stderr
msg = traceback.format_exc() # 或转成字符串存日志
print("已记录错误,长度:", len(msg))
在 except 里只打印 e 常常看不出是哪一层炸的,traceback 会把调用链完整还给你。
6. timeit:别用感觉判断快慢
from timeit import timeit
a = timeit('"-".join(str(n) for n in range(100))', number=10000)
b = timeit('s = ""\nfor n in range(100): s += str(n)', number=10000)
print(f"join: {a:.4f}s 加号拼接: {b:.4f}s")
timeit 会重复跑很多次取稳定结果,避免「只跑一次被系统卡顿带偏」。判断哪种写法快,用它,不要靠直觉。
7. python -i:跑完别关,进去看看
python3 -i demo.py
脚本执行完不退出,直接带着所有全局变量进入交互模式。可以现场检查 data 到底是什么、func(3) 返回什么——排查「结果不对但没报错」这类问题特别顺手。
配合 breakpoint() 更好用:断点处 c 继续跑到结束,解释器还开着,接着查。
一张对照表
| 场景 | 别用 | 用 |
|---|---|---|
| 临时看变量值 | print("x =", x) | f"{x=}" |
| 不确定哪一步错 | 到处插 print | breakpoint() |
| 打印嵌套数据 | print | pprint |
| 需要长期保留的日志 | print | logging |
| 只看一句异常信息 | print(e) | traceback |
| 比较两种写法快慢 | 掐表 | timeit |
| 结果不对但没报错 | 反复改代码重跑 | python -i |
村长划重点:调试的核心不是「工具多」,而是先缩小范围。先确定是数据错、逻辑错还是环境错,再决定用哪个工具。一上来就打十几个 print,只会把自己淹了。
我是村长,祝愿大家的代码都少几个 bug,早点下班。
