跳到主要内容

少写 print,早点下班:村长的 7 个 Python 调试小技巧

· 阅读需 4 分钟
村长
不好奇编程站长 · B站「村长不好奇」

村长

新手调试三件套:加 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=}"
不确定哪一步错到处插 printbreakpoint()
打印嵌套数据printpprint
需要长期保留的日志printlogging
只看一句异常信息print(e)traceback
比较两种写法快慢掐表timeit
结果不对但没报错反复改代码重跑python -i

村长划重点:调试的核心不是「工具多」,而是先缩小范围。先确定是数据错、逻辑错还是环境错,再决定用哪个工具。一上来就打十几个 print,只会把自己淹了。

我是村长,祝愿大家的代码都少几个 bug,早点下班。