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

重写__getattr__代理其他对象方法时如何加类型提示实现IDE补全?

实现动态代理类属性自动补全的两种常用方案

方案1:固定代理单个类,最简实现

如果你的Pizza类固定只代理Topping的属性,直接让Pizza类继承Topping即可,类型检查器会通过继承关系识别到Pizza实例拥有Topping的所有属性和方法,实际运行时还是通过你写的__getattr__转发请求,不会产生冲突:

class Topping:
    def __init__(self, name: str) -> None:
        self.name = name

    def topping_cost(self) -> int:
        return 3

# 继承Topping仅用于给类型检查器提供提示,不影响运行逻辑
class Pizza(Topping):
    def __init__(self, topping: Topping) -> None:
        self.topping = topping

    def __getattr__(self, attr):
        if hasattr(self.topping, attr):
            return getattr(self.topping, attr)
        raise AttributeError(f'Missing attr {attr!r}')

方案2:通用代理类,支持代理任意类型

如果你的项目有多个需要动态代理的场景,可以用泛型封装通用代理父类,后续所有需要代理功能的类继承该父类即可,复用性更高:

from typing import TypeVar, Generic, Any

T = TypeVar('T')

# 通用代理父类,泛型参数T为被代理的类类型
class BaseDelegate(Generic[T]):
    def __init__(self, delegate_obj: T) -> None:
        self._delegate_obj = delegate_obj

    def __getattr__(self, attr: str) -> Any:
        if hasattr(self._delegate_obj, attr):
            return getattr(self._delegate_obj, attr)
        raise AttributeError(f'Missing attribute {attr!r}')

class Topping:
    def __init__(self, name: str) -> None:
        self.name = name

    def topping_cost(self) -> int:
        return 3

# 声明代理的目标类型为Topping,IDE会自动识别Topping的所有属性和方法
class Pizza(BaseDelegate[Topping]):
    def __init__(self, topping: Topping) -> None:
        super().__init__(topping)
        # 可自定义Pizza本身的属性和方法
        self.size = "12寸"

    def calc_total_price(self) -> int:
        # 可以直接调用被代理的Topping方法,IDE会自动补全
        return 25 + self.topping_cost()

效果验证

两种方案都可以让你在调用pizza.topping_cost()时获得IDE的自动补全提示,同时mypy、pyright等类型检查工具也不会报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 09:24:03