如何创建兼容pyright的泛型Annotated类型别名AFoo[T, x]?
如何创建兼容pyright的泛型Annotated类型别名AFoo[T, x]?
我懂你现在的需求:想定义一个泛型类型别名AFoo[T, x],等价于Annotated[Foo[T], x],既要让pyright能正确识别类型,又能方便提取里面的类型参数T和元数据x。你之前试的两种方法都踩了坑,我来给你说个可行的方案。
先分析下你之前的问题:
- 第一种直接用类型别名的方式,
AFoo = Annotated[Foo[T], Any],这里的T没有被正确绑定成泛型参数,pyright没法识别AFoo[str, "bar"]这种用法,它会把整个Annotated[...]当成固定类型,而非带参数的泛型。 - 第二种用
__class_getitem__的方式,逻辑上能返回正确的Annotated对象,但pyright对这种动态生成的类型支持不佳,会错误地把AFoo[str, "bar"]解析成Foo[str, "bar"],而非Annotated[Foo[str], "bar"]。
下面是两种可行的解决思路:
方案一:使用泛型类型别名(推荐)
从Python 3.12开始,官方支持了泛型类型别名的语法,pyright也能完美识别:
from typing import TypeVar, Annotated, TypeAlias T = TypeVar("T") X = TypeVar("X") # 用来标记元数据的类型 # 定义泛型类型别名 AFoo: TypeAlias = Annotated[Foo[T], X]
如果是Python 3.11及以下版本,可以用Generic辅助定义,让pyright正确推断:
from typing import TypeVar, Annotated, Generic T = TypeVar("T") X = TypeVar("X") class _AFoo(Generic[T, X]): pass # 用_AFoo做泛型标记,实际指向Annotated[Foo[T], X] AFoo = Annotated[Foo[T], X]
这样使用AFoo[str, "bar"]时,pyright会正确识别它是Annotated[Foo[str], "bar"],不会误判为Foo的双参数泛型。
方案二:类型工厂函数+提取工具
如果泛型别名方式仍有问题,可以写一个类型工厂函数,再配套提取元数据和类型的工具:
from typing import TypeVar, Annotated, get_args, get_origin T = TypeVar("T") def AFoo(t: type[T], x): return Annotated[Foo[t], x] # 提取AFoo里的类型和元数据 def extract_afoo_info(annotated_type): if get_origin(annotated_type) is Annotated: foo_type, metadata = get_args(annotated_type) if get_origin(foo_type) is Foo: t = get_args(foo_type)[0] return t, metadata raise ValueError("输入不是合法的AFoo类型")
这种方式下,AFoo(str, "bar")会生成Annotated[Foo[str], "bar"],pyright能正确识别该类型,extract_afoo_info也能轻松提取出T和x。
验证pyright兼容性
可以用这段代码测试:
def test_func(arg: AFoo[str, "bar"]) -> None: pass # 让pyright输出推断的类型 reveal_type(test_func.__annotations__["arg"]) # pyright应该输出:Annotated[Foo[str], "bar"]
这样既满足了pyright的类型检查要求,又能方便提取类型参数和元数据。
备注:内容来源于stack exchange,提问作者tierriminator
相关产品推荐
相关产品推荐

