Python垃圾回收未正常生效?Logger循环运行时日志重复输出问题求助
问题根因
- Python标准库
logging的logger实例是全局托管的,调用logging.getLogger(name)时,相同name的logger永远返回同一个全局实例,不受你本地变量回收影响 - 你每次循环初始化
Logger类时,都在给全局的info、error两个logger重复添加FileHandler和StreamHandler,每循环1次新增2个Handler,第N次循环时,打1条日志会被N个Handler同时处理,就会输出N条重复日志 - 你之前的两种解决方案无效的原因:
- 将本地变量设为
None没用,logging模块内部依然持有logger和handler的引用,不会被垃圾回收 - 你编写的单例模式存在两处错误:一是
__new__仅按类做实例缓存,不管传参是否不同都返回同一个实例,不符合多模块不同logger的使用场景;二是即便单例创建成功,每次调用Logger()时__init__方法依然会执行,还是会重复添加Handler
- 将本地变量设为
修复方案
方案1:初始化前清空已有Handler(最快捷修复)
在Logger类的__init__方法中,添加Handler之前先清空logger已有的Handler,避免重复叠加,修改示例:
#----------------- Error logger ------------------- self.__error_logger = logging.getLogger("error") self.__error_logger.setLevel(logging.ERROR) # 新增:清空已有Handler if self.__error_logger.hasHandlers(): self.__error_logger.handlers.clear() # 后面接你原来的添加FileHandler、StreamHandler的逻辑 #----------------- Info logger ------------------- self.__info_logger = logging.getLogger("info") self.__info_logger.setLevel(logging.INFO) # 新增:清空已有Handler if self.__info_logger.hasHandlers(): self.__info_logger.handlers.clear() # 后面接你原来的添加FileHandler、StreamHandler的逻辑
方案2:修复单例模式,避免重复执行初始化逻辑
如果要保留单例特性,需要同时修改__new__和__init__逻辑:
- 修改
__new__方法,按moduleName和path作为缓存key,支持不同模块创建不同的logger实例 - 给实例添加初始化标记,避免
__init__重复执行
修改示例:
def __new__(cls, moduleName, path = "../logging/"): # 按模块名和路径作为缓存key,支持多模块不同实例 cache_key = (moduleName, path) if cache_key not in cls._instances: cls._instances[cache_key] = super(Logger, cls).__new__(cls) return cls._instances[cache_key] def __init__(self, moduleName, path = "../logging/"): # 已初始化过就直接返回,不重复添加Handler if hasattr(self, '_is_init'): return self._is_init = True # 后面接你原来的初始化逻辑
方案3:全局仅初始化一次logger(最佳实践)
不要在每次循环里初始化Logger实例,把logger初始化逻辑移到循环外部,全局初始化一次后循环内复用即可,从根源避免重复初始化的问题。
内容的提问来源于stack exchange,提问作者user3793935
相关产品推荐
相关产品推荐

