You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在自定义Python类中扩展logging模块方法且不影响vars()输出?

解决自定义类扩展logging方法同时保持vars()干净的问题

我来帮你搞定这个需求!你想要给自定义Test类扩展logging模块的自定义级别print方法,同时要求调用vars()时只显示你自己定义的属性,不能把这个日志方法也包含进来对吧?先梳理下你尝试的三种方法的问题,再给出更优雅的实现方案:

现有方法的问题分析

方法一:绑定为实例属性

把logger.print赋值给实例属性self.print,虽然能直接调用,但vars()会把这个方法当作实例属性输出,不符合你“仅显示非logging方法属性”的要求。

# Test.py
import logging
logger = logging.getLogger('console')

class Test:
    def __init__(self):
        self._some_obj = True
        self.print = logger.print  # 绑定为实例属性

# main.py
print(vars(Test()))  # 输出 {'_some_obj': True, 'print': <bound method Logger.print of <Logger console (PRINT)>>}

方法二:设为类属性

将logger.print设为类属性后,vars()的输出确实干净了,但直接覆盖了Python内置的print方法,会导致代码中无法正常使用默认的打印功能,风险很高。

# Test.py
import logging
logger = logging.getLogger('console')

class Test:
    print = logger.print  # 覆盖了默认print方法
    def __init__(self):
        self._some_obj = True

# main.py
print(vars(Test()))  # 输出 {'_some_obj': True},但类的print被覆盖

方法三:编写包装方法

手动写包装方法虽然能避开前两个问题,但代码冗余度高,而且如果logger.print有可选参数(比如exc_info、extra等),你需要手动处理参数传递,非常不优雅。

# Test.py
import logging
logger = logging.getLogger('console')

class Test:
    def __init__(self):
        self._some_obj = True
    def print(self, msg):  # 包装方法,参数处理麻烦
        logger.print(msg)

# main.py
print(vars(Test()))  # 输出 {'_some_obj': True}

推荐方案:使用__getattr__魔法方法

Python的__getattr__方法会在访问实例上不存在的属性时被调用,利用这个特性,我们可以动态返回logger.print方法,既不会在vars()中留下痕迹,也不会覆盖默认方法,还能自动传递所有参数。

完整实现代码

首先确保你已经注册了自定义的PRINT日志级别(如果还没做的话),然后实现Test类:

# Test.py
import logging

# 注册自定义PRINT级别(级别值设为DEBUG+5,比DEBUG高一点)
PRINT_LEVEL = logging.DEBUG + 5
logging.addLevelName(PRINT_LEVEL, 'PRINT')

# 给Logger类添加print方法
def _logger_print(self, msg, *args, **kwargs):
    if self.isEnabledFor(PRINT_LEVEL):
        self._log(PRINT_LEVEL, msg, args, **kwargs)

logging.Logger.print = _logger_print

logger = logging.getLogger('console')

class Test:
    def __init__(self):
        self._some_obj = True
    
    def __getattr__(self, name):
        # 当访问的属性是'print'时,返回logger的print方法并绑定当前实例上下文
        if name == 'print':
            return logger.print.__get__(self, Test)
        # 其他属性按默认逻辑处理,抛出AttributeError
        raise AttributeError(f"'Test' object has no attribute '{name}'")

测试效果

# main.py
from Test import Test

t = Test()
# 调用自定义日志方法,支持所有logger.print的参数
t.print("This is a custom log message", exc_info=True)
# 查看vars()结果,仅显示自定义属性
print(vars(t))  # 输出 {'_some_obj': True}
# 默认print方法依然可用
print("Default print works normally!")

方案优势

  • vars()干净无冗余:__getattr__是动态处理属性访问,没有给实例或类添加实际的属性,所以vars()只会显示你定义的_some_obj
  • 不覆盖默认方法:只有当实例上找不到print属性时才会触发__getattr__,默认的print函数完全不受影响
  • 参数自动传递:返回的是logger.print的绑定方法,所有可选参数(如exc_info、extra)都能直接使用,无需手动处理
  • Pythonic且简洁:利用Python的魔法方法特性,代码简洁优雅,避免了冗余的包装方法

内容的提问来源于stack exchange,提问作者als9xd

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 06:55:09