logging.config加载自定义类遇路径错误与循环导入问题求助
为什么同目录时正常
当log_conf.py和业务模块在同一目录时,Python默认会把当前工作目录加入sys.path,所以logging.config.fileConfig加载logger.ini时,能直接找到log_conf模块并导入Custom格式化类。同时,此时log_conf.py里调用fileConfig的时机不会触发循环——业务模块先导入log_conf,log_conf完整定义完Custom类后才执行fileConfig,这时候Custom已经存在,不会有加载顺序问题。
移到myconf目录后出问题的原因
1. 模块搜索路径问题
如果myconf目录没有被标记为Python包(缺少__init__.py文件),Python的sys.path里不会自动包含myconf的父目录路径,直接在logger.ini里写myconf.log_conf.Custom会触发ModuleNotFoundError,因为解释器找不到myconf这个模块。
就算myconf是包(有__init__.py),如果脚本运行时的工作目录不是myconf的父目录,sys.path里没包含这个父目录,同样会找不到模块。
2. 循环导入问题
如果log_conf.py的顶层代码逻辑是:先定义Custom类,立刻调用logging.config.fileConfig加载logger.ini,而logger.ini里又指定class=myconf.log_conf.Custom——这就会触发循环导入:
- 业务模块导入
myconf.log_conf时,log_conf模块开始执行,先定义Custom类,接着调用fileConfig; fileConfig解析logger.ini,发现需要导入myconf.log_conf.Custom,于是尝试再次导入myconf.log_conf;- 但此时
myconf.log_conf模块还在初始化过程中(代码没执行完),模块对象已经存在但Custom类还没完全注册,解释器返回未完成的模块对象,导致访问Custom时出现AttributeError。
解决办法
第一步:把myconf变成合法Python包
在myconf目录下创建空的__init__.py文件(Python 3.3+支持命名空间包,但显式添加更稳妥)。
第二步:调整模块搜索路径
确保myconf的父目录被加入sys.path,可以在启动脚本最开头添加:
import sys from pathlib import Path # 假设启动脚本和myconf在同一父目录下 sys.path.append(str(Path(__file__).parent))
第三步:避免循环导入
把log_conf.py里调用fileConfig的代码从顶层移到函数里,让业务模块在导入log_conf后再主动调用初始化:
# myconf/log_conf.py from pythonjsonlogger import jsonlogger import logging.config import os class Custom(jsonlogger.JsonFormatter): # 你的格式化逻辑 def format(self, record): # 自定义处理 return super().format(record) def setup_logging(): # 用当前文件路径拼接配置文件路径,避免工作目录问题 config_path = os.path.join(os.path.dirname(__file__), "logger.ini") logging.config.fileConfig(config_path)
然后在业务模块里:
from myconf.log_conf import setup_logging setup_logging()
同时把logger.ini里的formatter class配置为myconf.log_conf.Custom。
这样调整后,setup_logging是在Custom类完全定义并导入后才被调用,fileConfig再去导入myconf.log_conf.Custom时,模块已经初始化完成,不会出现循环导入问题。
内容的提问来源于stack exchange,提问作者red888

