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

如何为Python中__getattr__方法的返回值添加正确类型注解?

为包装类的__getattr__添加精确类型注解

针对你用包装类转发属性的场景,以下是几种可行的类型注解方案,避免使用object或Any,同时无需手动编写大量重载:

方案1:用Generic和TypeVar绑定被包装类型

通过Generic和TypeVar将包装器与被包装类关联,结合cast让类型检查器识别返回值与被包装实例属性的类型一致性:

from typing import TypeVar, Generic, cast

T = TypeVar('T')

class Foo:
    def __init__(self) -> None:
        self.restaurant: str = "taco bell"
        self.finger_count: int = 10
        self.login_info: dict[str, str] = {
            "username": "SilentHare",
            "password": "123passw0rd",
        }

    def foo_method(self) -> None:
        print("This method is also an attribute")
        print(f"Login info is {self.login_info}")

class FooWrapper(Generic[T]):
    def __init__(self, instance: T) -> None:
        self.foo_instance: T = instance

    def __getattr__(self, attr: str) -> T:
        return cast(T, getattr(self.foo_instance, attr))

# 使用示例
wrapper = FooWrapper(Foo())
wrapper.foo_method()  # 类型检查器无报错
reveal_type(wrapper.restaurant)  # mypy会推断为str(需开启严格模式)

方案2:自动生成__getattr__重载

利用反射自动为被包装类的所有非私有属性生成重载,无需手动维护:

from typing import overload, Literal
import inspect

class Foo:
    def __init__(self) -> None:
        self.restaurant: str = "taco bell"
        self.finger_count: int = 10
        self.login_info: dict[str, str] = {
            "username": "SilentHare",
            "password": "123passw0rd",
        }

    def foo_method(self) -> None:
        print("This method is also an attribute")
        print(f"Login info is {self.login_info}")

class FooWrapper:
    def __init__(self) -> None:
        self.foo_instance: Foo = Foo()

    # 自动生成所有属性的重载
    for name, _ in inspect.getmembers(Foo, predicate=lambda x: not inspect.isroutine(x) or inspect.isfunction(x)):
        if not name.startswith('_'):
            # 生成针对当前属性的重载
            @overload
            def __getattr__(self, attr: Literal[name]) -> type(getattr(Foo, name)): ...
            locals()['__getattr__'] = __getattr__

    def __getattr__(self, attr: str):
        if hasattr(self.foo_instance, attr):
            return getattr(self.foo_instance, attr)
        raise AttributeError

这段代码会在模块加载时自动遍历Foo的属性,生成对应的重载,类型检查器能精确识别每个属性的类型。

方案3:使用mypy插件扩展类型系统

如果前两种方案无法满足需求,可以编写mypy插件,让类型检查器直接理解__getattr__的转发逻辑。插件可以动态分析被包装类的属性,为包装器添加精确的类型注解,无需手动维护代码。

总结

  • 方案1简单易行,适合大多数场景,虽依赖cast但能避免Any的模糊性;
  • 方案2通过自动生成重载实现精确类型推断,适合被包装类频繁更新的场景;
  • 方案3是最灵活的方案,但需要熟悉mypy的插件开发API。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 22:54:53