如何为函数与对应参数元组的列表添加MyPy类型注解?
问题描述
我在程序中创建了一个元组列表,每个元组包含一个函数和一个可解包传入该函数的参数元组,示例代码如下:
def func1(idx: int, enable: bool) -> None: # Do thing pass def func2(enable: bool) -> None: # Do thing pass my_tuple_list = [] my_tuple_list.append((func1, (2, True))) # Tuple[Callable[[int, bool], None], Tuple[int, bool]] my_tuple_list.append((func2, (False,))) # Tuple[Callable[[bool], None], Tuple[bool]] for func, args in my_tuple_list: func(*args)
由于这些函数的参数类型不同,我希望让MyPy能够识别参数元组的类型与函数期望的参数类型完全匹配。目前我只能为每种函数分别定义TypeAlias:
TupleFunc1: TypeAlias = Tuple[Callable[[bool], None], Tuple[bool]] TupleFunc2: TypeAlias = Tuple[Callable[[int, bool], None], Tuple[int, bool]] TupleFunc3: TypeAlias = Tuple[Callable[[str], None], Tuple[str]]
我期望能通过泛型方式定义一个通用的TypeAlias,例如:
TupleFunc: TypeAlias = Tuple[Callable[[T], None], Tuple[T]]
起初我考虑用Union,但后续新增函数时会导致维护复杂。我也尝试过ParamSpec和TypeVar,但总会出现MyPy错误。请问该如何实现这一需求?
解决方案
你可以结合ParamSpec和TypeVar来定义通用的泛型类型别名,完美匹配函数参数与对应参数元组的类型:
from typing import Callable, Tuple, TypeAlias, ParamSpec, TypeVar P = ParamSpec("P") R = TypeVar("R") # 定义通用的泛型类型别名:(函数, 匹配函数参数的元组) FuncWithArgs: TypeAlias = Tuple[Callable[P, R], P.args] # 示例函数 def func1(idx: int, enable: bool) -> None: pass def func2(enable: bool) -> None: pass def func3(name: str) -> None: pass # 指定列表的类型为泛型的联合,让MyPy自动推导每个元素的类型匹配 my_tuple_list: list[FuncWithArgs] = [] my_tuple_list.append((func1, (2, True))) # 类型检查通过 my_tuple_list.append((func2, (False,))) # 类型检查通过 my_tuple_list.append((func3, ("Alice",))) # 类型检查通过 # 错误示例:参数元组不匹配函数参数,MyPy会报错 # my_tuple_list.append((func1, (False,))) # 类型错误:参数数量/类型不匹配 for func, args in my_tuple_list: func(*args) # MyPy能正确识别参数类型,无报错
关键说明
ParamSpec("P")用于捕获函数的完整参数签名,包括参数的数量、类型和顺序P.args会自动映射为该函数参数对应的元组类型,确保参数元组和函数的参数要求完全一致- 定义的
FuncWithArgs是泛型类型别名,能适配任意参数签名的函数和对应的参数元组 - 新增函数时直接往列表添加符合格式的元素即可,无需修改类型定义,MyPy会自动完成校验
如果需要强制函数返回值为None,可以将R固定为None,简化类型别名:
FuncWithArgs: TypeAlias = Tuple[Callable[P, None], P.args]
内容的提问来源于stack exchange,提问作者Jay
相关产品推荐
相关产品推荐

