如何在Python中代理类的所有继承方法
问题分析与解决方案
错误原因
你遇到的RecursionError是因为在自定义的__getattribute__方法中访问self._options时,会再次触发__getattribute__调用——Python中任何实例属性的访问都会经过这个方法,从而形成无限递归,最终超出递归深度限制。
可行解决方案
方案一:修复__getattribute__,安全拦截父类方法
通过直接调用object.__getattribute__绕过自定义逻辑获取属性,避免递归;同时仅对父类的方法执行前置处理,不影响其他属性的正常访问。
from typing import Any class Father(): def fatherMethodOne(self): print("This is father method one") def fatherMethodTwo(self): print("This is father method two") class Child(Father): ALLOWED_OPTIONS = ["test"] def __init__(self) -> None: super().__init__() self._options = { "test": True } def __getattribute__(self, name: str) -> Any: # 直接通过object的__getattribute__获取_options,避免递归 options = object.__getattribute__(self, '_options') # 执行_options合法性检查 for key in options.keys(): if key not in Child.ALLOWED_OPTIONS: raise KeyError(f"Key '{key}' not allowed") # 获取目标属性/方法 attr = super().__getattribute__(name) # 仅对父类定义的可调用方法添加前置逻辑 if name in dir(Father) and callable(attr): def wrapper(*args, **kwargs): print(f"执行前置操作:检查_options完成") return attr(*args, **kwargs) return wrapper return attr # 测试 Child().fatherMethodOne()
方案二:使用元类自动包装父类方法
通过元类在类创建阶段自动包装所有继承自父类的方法,无需手动修改__getattribute__,逻辑更清晰。
from typing import Any, Type class MethodWrapperMeta(type): def __new__(cls, name: str, bases: tuple[type, ...], namespace: dict[str, Any]) -> Type: # 遍历所有父类的方法 for base in bases: for attr_name, attr in base.__dict__.items(): # 跳过特殊方法(如__init__)和子类已重写的方法 if callable(attr) and not attr_name.startswith('__') and attr_name not in namespace: def wrapper_func(func): def wrapper(self, *args, **kwargs): # 执行前置逻辑 for key in self._options.keys(): if key not in self.ALLOWED_OPTIONS: raise KeyError(f"Key '{key}' not allowed") print(f"执行前置操作:检查_options完成") return func(self, *args, **kwargs) return wrapper namespace[attr_name] = wrapper_func(attr) return super().__new__(cls, name, bases, namespace) class Father(): def fatherMethodOne(self): print("This is father method one") def fatherMethodTwo(self): print("This is father method two") class Child(Father, metaclass=MethodWrapperMeta): ALLOWED_OPTIONS = ["test"] def __init__(self) -> None: super().__init__() self._options = { "test": True } # 测试 Child().fatherMethodTwo()
方案对比
- 方案一:动态拦截所有属性访问,适配父类后续新增方法,但需要准确区分需要拦截的目标属性,避免影响非方法属性。
- 方案二:在类创建时完成方法包装,性能更优,逻辑更直观,但无法拦截父类动态添加的方法(适合父类方法静态定义的场景)。
内容的提问来源于stack exchange,提问作者Matheus
相关产品推荐
相关产品推荐

