如何为类自身定义的实例方法附加统一额外功能?__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
问题
- 如何定义
__getattribute__实现需求且避免递归错误? - 是否有
__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
相关产品推荐
相关产品推荐

