该用print时:调试临时变量、5分钟内删除的输出、一次性脚本无日志需求;否则应统一用logging,避免混用导致维护困难。

什么时候该用 print,而不是 logging
调试临时变量、5 分钟内要删掉的输出、脚本一次性跑完且不需留存记录——这时候用 print 更直接。它没配置开销,不依赖层级,输完就出,适合“我只想看看这个值是不是 None”。但一旦涉及多环境(本地/测试/生产)、需要开关控制、或想区分“警告”和“错误”,print 就开始漏风了。
常见错误现象:print 残留没删,上线后疯狂刷屏;或者把 print("debug: x=", x) 硬塞进循环,拖慢执行还污染日志流。
- 只在开发阶段快速验证,且明确计划删除
- 脚本无日志需求(比如 CLI 工具的简单反馈,用
print+sys.stderr更合适) - 不想引入额外配置(如
basicConfig或 logger 实例)
logging 的最低可用配置怎么写才不踩坑
很多人一上来就抄 20 行配置,结果发现 logger.info("hello") 没输出——其实是没调 logging.basicConfig(),或者调得太晚(在 import 其他模块之后)。最简能用的配置就一行:
logging.basicConfig(level=logging.INFO)
这行必须在任何 logging.getLogger() 调用之前执行,否则 logger 会用默认的 WARNING 级别,导致 INFO 日志被静默丢弃。
立即学习“Python免费学习笔记(深入)”;
- 级别设太低(如
DEBUG)会导致日志爆炸,尤其用了第三方库时 - 不指定
format时,默认不带时间戳和模块名,排查时抓瞎 - 多个模块各自调
basicConfig只有第一个生效,后续无效
为什么不要在库代码里用 basicConfig
你写的包被别人 import 时,如果内部执行了 basicConfig,就会抢走主程序的日志控制权——对方想输出到文件,你的库却把所有日志打到控制台,还改了全局格式。这是破坏性行为。
正确做法:库代码只用 logging.getLogger(__name__) 获取 logger,不配置 handler、不设 level、不调 basicConfig。配置责任交给使用者,在主程序入口统一处理。
- 库中 logger 命名用
__name__,自动继承模块路径,方便按模块开关日志 - 主程序可以用
logging.getLogger("mylib.submodule").setLevel(logging.DEBUG)精确调试某部分 - 若库真要默认输出(如 CLI 工具),应提供显式初始化函数,而非静默调
basicConfig
print 和 logging 混用时的性能与线程问题
在高并发或高频循环里混用二者,容易暴露底层差异:print 是同步写 sys.stdout,而 logging 默认也是同步,但加了锁。如果同时有 10 个线程狂打 print,可能输出错行(如两行内容挤在同一行);而 logging 虽然保序,但锁竞争会让性能掉得明显。
- 线上服务禁用
print,哪怕只是临时加的——它绕过所有日志治理机制 - 高频场景下,用
logging.debug前先判断logger.isEnabledFor(logging.DEBUG),避免字符串拼接开销 - 真要极致性能,考虑异步 handler(如
concurrent_log_handler),但多数情况没必要
真正麻烦的不是选哪个,而是同一项目里两种风格并存:有人改了 print 为 logging 却忘了改 level,有人在日志里写 print(f"result: {x}")——这种混合态比纯用哪个都难维护。










