Python 中泛型的实现

在学习 Python 3.10 新特性时,其中有个类型别名(TypeAlias), 所举的例子是

1StrCache = 'Cache[str]' # a type alias<br />
2LOG_PREFIX = 'LOG[DEBUG]' # a module constant

可写成
1StrCache: TypeAlias = 'Cache[str]' # a type alias<br />
2LOG_PREFIX = 'LOG[DEBUG]' # a module constant

这让 StrCache 更像是一个类型别名,而不是一个看起来明显就是 Cache[str] 的字符串变量(实际上它确实是)。

本文不在 TypeAlias 本身,而是从 Cache[str] 能看出 Python 似乎也能支持像 Java 那样的泛型, 就像 Python 内置支持的 List[str] 或 list[str] 那样。

那么来看 Python 怎么去实现一个只能放入字符串的  Cache[str] Cache, 而不能放入别的类型。
 1from typing import TypeVar, Generic
 2
 3T = TypeVar('T')
 4
 5class Cache(Generic[T]):
 6    def __init__(self) -> None:
 7        self.items: dict[str, T] = {}
 8
 9    def put(self, key: str, item: T) -> None:
10        self.items[key] = item                  # Line 13
11
12    def get(self, key: str) -> T:
13        return self.items.get(key)

我们依然用到的是 Python 的 typing 模块,所以上面代码仍然是属于类 type hints 的范畴,对 Python 解释器不构成约束,只会影响到 mypy 这样的检查工具

使用上面的类
1cache = Cache[str]()
2
3cache.put('a', 'abc')
4print(cache.get('a'))
5
6cache.put('b', 123)                           # Line 21
7print(cache.get('b'))

使用 python test.py 命令执行一切正常,输出为
abc
123
但在 IntelliJ IDEA 中,上面高亮的第五行 cache.put('b', 123) 行上会提示
Expected type 'str' (matched generic type 'T'), got 'int' instead
如果用 mypy 来检测
$ mypy tt.py
tt.py:13: error: Incompatible return value type (got "Optional[T]", expected "T")
tt.py:21: error: Argument 2 to "put" of "Cache" has incompatible type "int"; expected "str"
Found 2 errors in 1 file (checked 1 source file)
typing 模块中除了上面用到的 Generic, TypeVar 外,还有更多的类型约束,像 Mapping, Iterator, Sequence。还有更多的类似于 Java 的泛型功能

泛型子类型

 1from typing import TypeVar, Generic
 2
 3T = TypeVar('T')
 4
 5class Cache(Generic[T]):
 6    pass
 7
 8
 9class TTLCache(Cache[T]):
10    pass

泛型函数

1from typing import TypeVar, Sequence
2
3T = TypeVar('T')      # Declare type variable
4
5def first(seq: Sequence[T]) -> T:   # Generic function
6    return seq[0]

更多用法,在此不一一列出。写自己的实现代码使用泛型的需要其实并不大,除非做第三方的通用库会用到泛型写法,这让别人用起来更清晰。

更多功能请参考 https://mypy.readthedocs.io/en/stable/generics.html

链接:
  1. mypy 0.961 document - Generics

  永久链接 https://yanbin.blog/python-generic-implementation/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。