如何使用TypeVarTuple为批量创建类实例的函数添加正确的类型注解?
如何使用TypeVarTuple为批量创建类实例的函数添加正确的类型注解?
你想要的这种类型注解在Python 3.12+(或配合typing_extensions兼容更早版本)是完全可以实现的,你的思路方向是对的,只是参数的类型语法需要调整一下。
正确的类型注解实现
我们可以通过TypeVarTuple定义可变的类型元组,再利用Unpack拆解这个元组,分别对应“类的类型”和“实例的类型”:
from typing import TypeVarTuple, Unpack # 定义可变类型元组Ts,代表要创建的实例的类型集合 Ts = TypeVarTuple("Ts") def f[*Ts]( *classes: Unpack[tuple[type[T] for T in Ts]] ) -> tuple[Unpack[Ts]]: return tuple(cls() for cls in classes)
这样写之后,mypy和Intellisense都能正确推断类型:
class A: pass class B: pass class C: pass a, b, c = f(A, B, C) reveal_type(a) # 会显示类型为A reveal_type(b) # 会显示类型为B reveal_type(c) # 会显示类型为C
为什么你的初始写法不行?
你之前尝试的type[*Ts]语法不符合规则,因为Unpack(也就是泛型里的*用法)只能用在可变参数的位置,而type[]的括号里是单个类型的声明位置,不能直接拆解类型元组。我们需要先构造一个由type[T]组成的元组,再用Unpack把它拆解成可变参数的类型,这样就符合语法要求了。
备选方案:重载(你提到的思路)
如果你的项目需要兼容不支持PEP 646(泛型可变参数)的Python版本,那你之前想到的重载方案确实可行,虽然繁琐但能解决问题。你可以写多个@overload来覆盖不同参数数量的情况:
from typing import overload, TypeVar T1 = TypeVar("T1") T2 = TypeVar("T2") T3 = TypeVar("T3") @overload def f[T1](cls1: type[T1]) -> tuple[T1]: ... @overload def f[T1, T2](cls1: type[T1], cls2: type[T2]) -> tuple[T1, T2]: ... @overload def f[T1, T2, T3](cls1: type[T1], cls2: type[T2], cls3: type[T3]) -> tuple[T1, T2, T3]: ... # 可根据实际需求继续添加更多重载,覆盖到你需要的参数数量上限 def f(*classes): return tuple(cls() for cls in classes)
这种方式的缺点是需要手动维护多个重载,没法无限扩展参数数量,但如果你的实际场景中调用这个函数时传入的类数量不会太多,这也是一个稳妥的选择。
备注:内容来源于stack exchange,提问作者Dan Gittik
相关产品推荐
相关产品推荐

