Python中如何为函数标注与类成员函数一致的返回类型?
问题描述
我正在使用Python 3.11,搭配mypy作为类型检查器。想要实现如下示例,但不知道foo_call的返回类型该如何定义,才能让它自动根据Foo的泛型参数(比如Bar)推断出my_func的返回类型:
from dataclasses import dataclass from abc import ABC, abstractmethod from typing import Any, TypeVar, Generic class MyBase(ABC): @abstractmethod def my_func(self, *args, **kwargs) -> Any: raise NotImplementedError class Bar(MyBase): def my_func(self, *args, **kwargs) -> int: return 5 class Baz(MyBase): def my_func(self, *args, **kwargs) -> str: return 'Hello' T = TypeVar('T', bound=MyBase) @dataclass class Foo(Generic[T]): value: T def foo_call(self) -> ???: # 这里该填什么?我想要类似T.my_func.__annotations__['return']的效果 return self.value.my_func() myFoo: Foo[Bar] = Foo(value=Bar()) myFoo.foo_call() # 希望这里能自动提示返回类型为int
我试过把myFoo声明为Foo[int],并把foo_call的返回类型设为T,但这样当Bar.my_func的返回类型变更时,无法自动同步。正确的实现方式是什么?
编辑补充
之前得到的方法有帮助,但存在两个问题:一是my_func返回类型变更时仍需多处更新类型提示;二是支持多个函数时要定义多个TypeVar,示例如下:
from dataclasses import dataclass from abc import ABC, abstractmethod from typing import TypeVar, Generic # 每新增一个方法就要加一个TypeVar T = TypeVar('T') TOther = TypeVar('TOther') class MyBase(ABC, Generic[T, TOther]): @abstractmethod def my_func(self, *args, **kwargs) -> T: raise NotImplementedError @abstractmethod def other_func(self, *args, **kwargs) -> TOther: raise NotImplementedError class Bar(MyBase[int, float]): def my_func(self, *args, **kwargs) -> int: return 5 def other_func(self, *args, **kwargs) -> float: return 6.2 @dataclass class Foo(Generic[T, TOther]): value: MyBase[T, TOther] def foo_call(self) -> T: return self.value.my_func() def foo_other(self) -> TOther: return self.value.other_func() myFoo: Foo[int, float] = Foo(value=Bar()) myFoo.foo_call() myFoo.foo_other()
我理想的效果是:只需将MyBase的子类类型作为Foo的泛型参数(比如myFoo: Foo[Bar] = ...),让foo_call等方法的返回类型自动据此推断。
解决方案
可以使用typing_extensions.ReturnType(Python 3.12+可直接用typing.ReturnType)来提取类方法的返回类型,无需手动维护多个TypeVar,且能自动同步方法返回类型的变更:
实现代码
from dataclasses import dataclass from abc import ABC, abstractmethod from typing import TypeVar, Generic from typing_extensions import ReturnType # Python 3.12+ 替换为 from typing import ReturnType # 定义绑定到MyBase的TypeVar T = TypeVar('T', bound='MyBase') class MyBase(ABC): @abstractmethod def my_func(self, *args, **kwargs) -> Any: raise NotImplementedError @abstractmethod def other_func(self, *args, **kwargs) -> Any: raise NotImplementedError class Bar(MyBase): def my_func(self, *args, **kwargs) -> int: return 5 def other_func(self, *args, **kwargs) -> float: return 6.2 class Baz(MyBase): def my_func(self, *args, **kwargs) -> str: return 'Hello' def other_func(self, *args, **kwargs) -> bool: return True @dataclass class Foo(Generic[T]): value: T # 直接提取T中my_func的返回类型 def foo_call(self) -> ReturnType[T.my_func]: return self.value.my_func() # 同理提取other_func的返回类型 def foo_other(self) -> ReturnType[T.other_func]: return self.value.other_func() # 使用时只需传入子类类型作为泛型参数 myFooBar: Foo[Bar] = Foo(value=Bar()) reveal_type(myFooBar.foo_call()) # mypy会提示:Revealed type is "builtins.int" reveal_type(myFooBar.foo_other()) # mypy会提示:Revealed type is "builtins.float" myFooBaz: Foo[Baz] = Foo(value=Baz()) reveal_type(myFooBaz.foo_call()) # mypy会提示:Revealed type is "builtins.str" reveal_type(myFooBaz.foo_other()) # mypy会提示:Revealed type is "builtins.bool"
说明
- 自动同步类型变更:当
Bar.my_func的返回类型从int改为str时,myFooBar.foo_call()的类型提示会自动更新,无需修改Foo类的代码。 - 无需额外TypeVar:新增方法时,只需在
Foo中添加对应方法,用ReturnType[T.新方法名]作为返回类型即可,无需定义新的TypeVar。 - 类型检查支持:mypy能正确识别
ReturnType[T.方法名]的类型,提供准确的代码提示和类型校验。
内容的提问来源于stack exchange,提问作者Mobious
相关产品推荐
相关产品推荐

