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

如何对Python typing.Generic类型本身进行类型注解?

如何在Python类型标注中表达泛型类本身(泛型构造器)

你提到的这个问题其实是Python类型系统里一个经典的痛点:如何标注那些**接收泛型类本身(比如List)、绑定具体类型后返回该泛型实例类型(比如List[int])**的函数,也就是你说的functor(函子)类型。下面结合你的尝试一步步拆解解决方案:

先分析你之前尝试的问题

  • 朴素方法用Generic作为类型:Generic只是泛型类的基类,不是泛型构造器的类型,所以mypy会报错,它不代表“可以被[]索引的泛型类”。
  • GenericMeta:这是旧版typing库的内部实现细节,属于未公开的API,不仅没被PEP收录,在Python 3.7+的标准库中已经被移除,完全不推荐依赖。
  • Mapping[Type, Type]:这个思路是错的,List不是Mapping,它只是支持__getitem__语法的鸭子类型,静态类型检查不会把它当成Mapping。
  • 宽松的Type写法:虽然能拦截apply(10, int)这种明显错误,但无法阻止apply(int, int)——因为int也是Type,但它不支持[]索引,会在运行时炸锅。

正确解决方案:用PEP 544的Protocol定义泛型构造器协议

PEP 544引入的Protocol正好解决了这个鸭子类型的静态标注问题:我们可以定义一个协议,描述“支持用[]接收类型参数、返回绑定后泛型类型”的行为,让mypy识别List、Dict这类泛型类符合这个协议。

具体代码实现

from typing import TypeVar, Type, Generic, Protocol
from typing_extensions import Self  # Python 3.11+可以用标准库的typing.Self

# 定义两个TypeVar:T代表泛型的参数类型,G代表绑定参数后的泛型类型(比如List[int])
T = TypeVar('T')
G = TypeVar('G', covariant=True)

class GenericConstructor(Protocol, Generic[T, G]):
    def __getitem__(self, item: Type[T]) -> Type[G]: ...

def apply(generic: GenericConstructor[T, G], param: Type[T]) -> Type[G]:
    return generic[param]

# 测试正确用法:mypy会识别出ListOfInts是List[int]
ListOfInts = apply(list, int)
assert ListOfInts == list[int]

# 测试错误用法:mypy会报错,因为int不支持__getitem__接收类型参数
apply(int, int)  # error: Argument 1 to "apply" has incompatible type "Type[int]"; expected "GenericConstructor[int, Any]"

关键说明

  1. Protocol的作用:GenericConstructor协议定义了__getitem__的签名,只要一个类型实现了这个方法(比如list、dict这些泛型类),mypy就会认为它符合该协议,不需要显式继承。
  2. TypeVar的协变性:G标记为covariant=True是因为泛型绑定后的类型(比如List[int])是泛型构造器(List)的协变产物,这样类型检查会更灵活。
  3. 兼容性:Python 3.9+可以直接用标准库的typing.Protocol;3.8及以下需要安装typing-extensions库来导入Protocol和Self。

关于你提到的Functor

你说得完全没错!这种泛型构造器在范畴论里就是函子——它接收一个类型(范畴里的对象),返回另一个类型,同时保持类型之间的映射关系。Haskell里用* -> *这种kind来描述它,而Python通过Protocol实现了近似的静态类型约束。

内容的提问来源于stack exchange,提问作者R2RT

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 07:50:14