You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何定义可接收非类型参数的typing特殊形式适配静态类型检查?

实现能接收非类型参数的自定义类型构造器(兼容mypy 1.11.1)

最直接的解决方案:用PEP 695泛型值参数

从Python 3.12和mypy 1.10版本开始,PEP 695支持定义接收**普通值(比如整数)**作为参数的泛型类型,刚好满足你的需求。直接这么写就行:

from typing import Annotated

# 定义泛型类型foo,要求参数N是整数
type foo[N: int] = Annotated[int, N]

# 用起来完全符合预期
foo5: foo[5]

这时候mypy会正确识别foo[5]等价于Annotated[int, 5],不会报任何错误。

为啥之前的写法都不行

1. 普通类加__class_getitem__

普通类默认只能接收类型作为索引参数,mypy会觉得foo[5]里的5不是合法的类型参数,所以抛出"foo" expects no type arguments错误。哪怕你在__class_getitem__里返回Annotated,mypy的类型检查逻辑也不认这种动态返回的类型。

2. 错用_SpecialForm

typing._SpecialForm是Python内部的私有API,装饰器需要传指定参数,而且自定义的这种特殊形式不会被mypy当成合法的类型构造器,所以会报Function is not valid as a type错误。

3. 直接用函数调用当注解

mypy不允许在类型注解里用baz(5)这种函数调用语法,只认baz[...]的索引形式,所以会提示你改成索引写法。

兼容旧版Python/mypy的替代方案

要是没法用PEP 695(比如Python版本低于3.12),可以结合Literal和Generic模拟,但得把参数写成字面量类型:

from typing import Generic, Literal, Annotated, TypeVar

# 定义绑定整数字面量的类型变量
N = TypeVar('N', bound=int)

class foo(Generic[N]):
    @classmethod
    def __class_getitem__(cls, param: Literal[int]) -> type[Annotated[int, param]]:
        return Annotated[int, param]

# 这里要写成foo[Literal[5]]而不是foo[5]
foo5: foo[Literal[5]]

这种写法下,mypy会正确识别foo[Literal[5]]等价于Annotated[int, 5],只是写法上多了个Literal。

内容的提问来源于stack exchange,提问作者Kuba hasn't forgotten Monica

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 22:52:45