如何基于Python函数返回值创建类型提示与类型别名?
Python中是否支持提取函数返回类型的类型提示?
问题背景
假设有一个返回复杂元组的函数:
def my_fn(): return (create_this(), create_that(), someotherstuff)
假设Pylance能推断出create_this()等函数的返回类型,会自动识别my_fn的返回类型为Tuple[Type1, Type2, Type3]。
当需要编写一个接收该返回值的函数时,常规的类型提示写法如下:
def process_fn_value(data: Tuple[Type1, Type2, Type3]): ...
这种写法过于冗长,希望能简化为更直观的形式:
def process_fn_value(data: ReturnOf[my_fn]): ...
尝试过两种自定义实现,但均无法被类型检查器正确解析:
尝试1:泛型函数提取返回类型
T = TypeVar('T') def RetVal(cb: Callable[[Any], T]): return type(cb()) def test_fn(): return "test" def test_consumer(arg: RetVal[test_fn]): return arg
尝试2:参考Generic[T]实现自定义类型
class ReturnValue(Type[T], _root=True): def __new__(func, cb: Callable[[], Generic[T]]) -> T: return type(cb()) def test_fn(): return [1,2,3] def test_consumer(arg: ReturnValue[test_fn]): return arg testtype = ReturnValue(test_fn)
注:已知可能存在其他代码写法规避该问题,但受限于现有代码库,仅希望做局部优化。
解决方案
Python标准类型系统(PEP 484及后续扩展)中没有内置的ReturnOf[func]语法,但可以通过以下几种方式实现类似效果:
1. 类型别名+get_type_hints(Python 3.11+)
利用typing.TypeAlias结合get_type_hints直接提取函数的返回类型,兼容性最好:
from typing import TypeAlias, get_type_hints def my_fn(): return (1, "abc", 3.14) # 提取my_fn的返回类型作为别名 MyFnReturn: TypeAlias = get_type_hints(my_fn)['return'] def process_fn_value(data: MyFnReturn): print(data[1]) # 类型检查器会识别参数为str类型
2. TypeVar绑定返回类型(Python 3.10+)
通过TypeVar绑定函数的返回类型,让类型检查器自动推断:
from typing import TypeVar, Callable T = TypeVar('T') def extract_return_type(cb: Callable[..., T]) -> type[T]: return type(cb()) def my_fn(): return (1, "abc", 3.14) # 绑定my_fn的返回类型到TypeVar MyFnReturn = TypeVar('MyFnReturn', bound=extract_return_type(my_fn)) def process_fn_value(data: MyFnReturn): print(data[0]) # 类型检查器会识别参数为int类型
3. 依赖类型检查器扩展(Pylance/Mypy)
部分主流类型检查器支持非标准的泛型语法,直接模拟ReturnOf效果:
from typing import TypeVar # 定义泛型类型标记 ReturnOf = TypeVar('ReturnOf') def my_fn(): return (1, "abc", 3.14) def process_fn_value(data: ReturnOf[my_fn]): print(data[2]) # Pylance可正确推断为float类型
注意:这种写法依赖检查器的扩展支持,不属于Python标准语法,跨检查器可能存在兼容性问题。
总结
Python标准库没有内置的ReturnOf[func]类型提示语法,但通过类型别名、TypeVar绑定或依赖检查器扩展,都可以实现提取函数返回类型的需求。其中,**类型别名+get_type_hints**的方式兼容性最好,适合大多数场景;依赖检查器扩展的写法最接近理想中的简洁形式,但需注意跨工具的兼容性。
内容的提问来源于stack exchange,提问作者Tomáš Zato
相关产品推荐
相关产品推荐

