如何覆盖模块__name__属性,解决继承父类方法日志模块名不符问题
问题根因
a.py中的LOG是模块级日志器,在模块首次加载时就完成初始化,绑定了a模块的名称。父类A的方法运行时始终调用该日志器,因此即使是子类B调用父类方法,日志默认也会显示a模块的信息。
可行解决方案
方案1:重写父类方法,临时替换日志对象的名称属性
在b.py的子类B中重写对应方法,调用父类逻辑前后临时修改a.LOG的名称,调用完成后立即恢复,不会影响其他地方对A类的调用:
# b.py import a class B(a.A): def name(self): # 暂存原日志名 original_log_name = a.LOG.name try: # 临时修改为当前模块名 a.LOG.name = __name__ # 调用父类原有逻辑 super().name() finally: # 无论是否报错都恢复原日志名,避免影响其他调用 a.LOG.name = original_log_name
该方案侵入性极低,仅影响B类调用对应方法时的日志输出,不会污染全局状态,适合单一场景使用。
方案2:给日志处理器添加自定义过滤器,动态修正模块名
如果需要批量处理所有继承自A的子类的日志输出,可以给对应日志器加过滤器,通过调用栈判断当前调用的类类型,动态替换模块名:
# 在项目日志初始化的位置添加如下过滤器 import logging import inspect import a def fix_inherit_log_filter(record): stack = inspect.stack() for frame_info in stack: if frame_info.function == 'name' and 'a.py' in frame_info.filename: # 获取方法绑定的self实例 self_obj = frame_info.frame.f_locals.get('self', None) if self_obj: # 替换为实例所属类对应的模块名 record.name = self_obj.__class__.__module__ break return True # 给a模块的日志器添加过滤器 a.LOG.addFilter(fix_inherit_log_filter)
该方案适合子类数量多、需要统一处理的场景,不需要修改每个子类的方法。
方案3:全局替换a模块的LOG对象
如果B是A的唯一调用方,可以直接在导入a之后替换a.LOG为自定义的日志器:
# b.py import a import logging # 替换a模块的LOG为b模块的日志器 a.LOG = logging.getLogger(__name__) class B(a.A): pass
注意该方案会影响所有调用A类方法的日志输出,若存在其他直接调用A类的逻辑,日志也会显示为b模块的名称,仅适合B是A唯一调用方的场景。
内容的提问来源于stack exchange,提问作者osflw
相关产品推荐
相关产品推荐

