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

如何让mypy识别泛型代理类仅拥有被代理类的属性?

让mypy识别泛型代理类的被代理属性

要解决mypy因__getattr__允许任意属性访问的问题,核心是让mypy明确代理类的属性完全继承自泛型参数C(被代理类)。以下是几种可行的泛型解决方案:

方案一:泛型__getattr__返回类型变量

通过给__getattr__返回一个类型变量,并配合类型断言,让mypy自动推断属性是否属于被代理类:

import typing as t
from dataclasses import dataclass

C = t.TypeVar('C')
T = t.TypeVar('T')

class Proxy(t.Generic[C]):
    def __init__(self, obj: C):
        self.obj = obj

    def __getattr__(self, name: str) -> T:
        # 用cast告知mypy返回值为被代理对象对应属性的类型
        return t.cast(T, getattr(self.obj, name))

@dataclass
class Data:
    foo: int

pd = Proxy(Data(42))
pd.foo  # 类型检查通过,mypy识别为int类型
pd.oof  # 类型检查报错:"Proxy[Data]" has no attribute "oof" [attr-defined]

优点:通用泛型方案,类型安全,运行时无额外开销,mypy能准确推断属性类型并拦截不存在的属性。

方案二:重载__class_getitem__模拟被代理类型

通过重载类的__class_getitem__方法,让mypy将Proxy[C]直接视为C类型,复用被代理类的属性检查逻辑:

import typing as t
from dataclasses import dataclass

C = t.TypeVar('C')

class Proxy(t.Generic[C]):
    def __init__(self, obj: C):
        self.obj = obj

    def __getattr__(self, name: str) -> t.Any:
        return getattr(self.obj, name)

    @classmethod
    def __class_getitem__(cls, item: t.Type[C]) -> t.Type[C]:
        # 让mypy认为Proxy[C]等价于C类型
        return item

@dataclass
class Data:
    foo: int

pd = Proxy(Data(42))
pd.foo  # 类型检查通过
pd.oof  # 类型检查报错:"Data" has no attribute "oof" [attr-defined]

说明:这是类型检查层面的小技巧,运行时pd仍是Proxy实例,但mypy会将其当作C实例处理,适合快速适配现有代码。

方案三:结合Protocol约束被代理类

如果需要限制被代理类必须具备特定属性,可以定义Protocol并绑定泛型参数:

import typing as t
from typing_extensions import Protocol
from dataclasses import dataclass

class HasFoo(Protocol):
    foo: int

C = t.TypeVar('C', bound=HasFoo)

class Proxy(t.Generic[C]):
    def __init__(self, obj: C):
        self.obj = obj

    def __getattr__(self, name: str) -> t.Any:
        return getattr(self.obj, name)

@dataclass
class Data(HasFoo):
    foo: int

pd = Proxy(Data(42))
pd.foo  # 类型检查通过
pd.oof  # 类型检查报错:"Proxy[Data]" has no attribute "oof" [attr-defined]

优点:类型检查更严格,适合需要约束被代理类属性的场景;缺点是灵活性稍差,无法代理任意类。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 09:25:57