python日志重复打印主因是handler重复添加或propagate未关闭:调用basicconfig()后又手动addhandler()且propagate=true,或多次addhandler未清理旧handler,或logger层级传播叠加,应清空handlers、设propagate=false、统一配置方式。

Python日志重复打印,通常不是代码写错了,而是日志器(Logger)被多次添加了处理器(Handler),尤其是根日志器(root logger)和自定义日志器之间发生 handler 冗余或传播(propagate)叠加。
根日志器与自定义日志器共存导致重复
当你调用 logging.basicConfig(),它会自动为 root logger 添加一个 StreamHandler;而如果你又手动创建了 Logger 并添加 Handler(比如 FileHandler),且未关闭 propagate,默认会向上冒泡到 root logger,结果同一条日志被两个 Handler 各输出一次。
- 检查是否同时用了
basicConfig()和手动logger.addHandler() - 对自定义 logger,设
logger.propagate = False可阻断向 root 传递 - 避免在模块导入时反复调用
basicConfig()(它只生效一次,但多次调用易掩盖配置意图)
多次调用 addHandler 而未去重
常见于函数内初始化日志器、或在循环/重载逻辑中反复添加 Handler。每次 addHandler() 都会新增一个输出通道,不清理旧 handler 就会造成 N 次重复。
- 添加前先清空:
logger.handlers.clear() - 或判断是否已有 handler:
if not logger.handlers: - 推荐在应用启动阶段一次性配置,而非每次获取 logger 都重新配
日志器层级关系引发的隐式叠加
Logger 是树状结构,比如 logger = logging.getLogger("a.b"),它默认会把日志传给 "a" 和 root。如果 "a" 和 root 都有 Handler,就可能重复。
立即学习“Python免费学习笔记(深入)”;
- 用
logging.getLogger(name).propagate = False关闭特定节点的传播 - 用
logging.getLogger().handlers查看 root 的 handlers - 用
logging.Logger.manager.loggerDict浏览所有已创建的 logger 实例(调试用)
配置方式混用:dictConfig + basicConfig 或手动配置
dictConfig 和 basicConfig 都会设置 root logger。若先调 dictConfig,再调 basicConfig,后者可能悄悄加回一个 StreamHandler。
- 统一使用一种配置方式:推荐
dictConfig(更清晰可控)或纯手动构造 - 配置前可重置:
logging.getLogger().handlers.clear()和logging.getLogger().setLevel(logging.NOTSET) - 加载配置后,用
logging.getLogger().manager.disable = 0确保未被禁用
日志重复本质是输出通道失控,核心思路就是:查 handler 数量、控 propagate、避重复添加、选唯一配置入口。理清这四点,90% 的重复问题都能快速定位。











