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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 20:49:55