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

如何为类自身定义的实例方法附加统一额外功能?__getattribute__使用咨询

Python代理类方法调用的通用处理方案

现有代码

class MyBaseClass:
    def method1(self):
        print('Hello 1')

class MyClass2:
    def __init__(self, inp):
        self.old_class = inp

    def __getattr__(self, item):
        if hasattr(self, item):
            print('Hello!')
            return getattr(self,item)
        else:
            return getattr(self.old_class, item)  

    def method2(self):
        print('Hello 2')

需求说明

调用MyClass2自身直接定义的方法时打印"Hello!",调用代理自MyBaseClass的方法时不打印。示例如下:

  • 直接调用基类方法:
    MyBaseClass().method1()
    # 输出:Hello 1
    
  • 通过MyClass2代理调用基类方法:
    MyClass2(MyBaseClass()).method1()
    # 输出:Hello 1
    
  • 调用MyClass2自身方法:
    MyClass2(MyBaseClass()).method2()
    # 输出:
    # Hello!
    # Hello 2
    

问题

  1. 如何定义__getattribute__实现需求且避免递归错误?
  2. 是否有__getattribute__的替代方案实现需求?

问题1:用__getattribute__实现需求

__getattribute__会拦截所有属性访问,直接调用getattr(self, item)会触发递归,必须借助object类的原生__getattribute__来获取属性,避免递归。具体实现如下:

class MyBaseClass:
    def method1(self):
        print('Hello 1')

class MyClass2:
    def __init__(self, inp):
        self.old_class = inp

    def __getattribute__(self, item):
        # 调用object的__getattribute__绕开当前方法,避免递归
        attr = object.__getattribute__(self, item)
        # 判断属性是否是MyClass2自身定义的可调用方法
        if item in MyClass2.__dict__ and callable(attr):
            print('Hello!')
        return attr

    def __getattr__(self, item):
        # 自身无该属性时,代理到old_class
        return getattr(self.old_class, item)

    def method2(self):
        print('Hello 2')

逻辑说明

  • 用object.__getattribute__(self, item)获取目标属性,避免触发自身的__getattribute__导致递归。
  • 通过item in MyClass2.__dict__判断属性是否是MyClass2自身定义的(排除继承属性和实例属性),同时判断是否为可调用方法。
  • 符合条件则打印Hello!,最后返回属性;代理的方法会触发__getattr__,不会进入打印逻辑。

问题2:替代方案

不需要修改__getattribute__,可以通过类装饰器或元类实现通用的方法包装逻辑。

方案1:类装饰器

遍历类的属性,给所有自定义方法添加前置打印逻辑:

def add_hello_decorator(cls):
    for name, attr in cls.__dict__.items():
        # 仅处理自定义普通方法,排除特殊方法(如__init__、__getattr__)
        if callable(attr) and not name.startswith('__'):
            def wrapper(*args, original_method=attr, **kwargs):
                print('Hello!')
                return original_method(*args, **kwargs)
            setattr(cls, name, wrapper)
    return cls

class MyBaseClass:
    def method1(self):
        print('Hello 1')

@add_hello_decorator
class MyClass2:
    def __init__(self, inp):
        self.old_class = inp

    def __getattr__(self, item):
        return getattr(self.old_class, item)  

    def method2(self):
        print('Hello 2')

方案2:元类

在类创建阶段自动修改方法,添加打印逻辑:

class HelloMeta(type):
    def __new__(cls, name, bases, attrs):
        for attr_name, attr_value in attrs.items():
            if callable(attr_value) and not attr_name.startswith('__'):
                def wrapper(*args, original_method=attr_value, **kwargs):
                    print('Hello!')
                    return original_method(*args, **kwargs)
                attrs[attr_name] = wrapper
        return super().__new__(cls, name, bases, attrs)

class MyBaseClass:
    def method1(self):
        print('Hello 1')

class MyClass2(metaclass=HelloMeta):
    def __init__(self, inp):
        self.old_class = inp

    def __getattr__(self, item):
        return getattr(self.old_class, item)  

    def method2(self):
        print('Hello 2')

逻辑说明

两种方案都是在类定义阶段,给MyClass2自身的方法套一层包装,调用时先打印Hello!再执行原方法;代理的方法由__getattr__处理,不会被包装,因此不会触发打印。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 07:23:27