本篇文件介绍 Python 中的 泛型(Generics)
Intro 在没有泛型的情况下, 会遇上以下几个问题:
难以表达意图
假设你编写了一个函数, 它接受一个列表, 并返回列表中的第一个元素. 在不使用类型提示的情况下, 这个函数可以处理任何类型的列表, 但我们无法在函数签名中表达"返回的元素的类型与列表中的元素类型相同"这个意图
def get_first_element(items): return items[0] 丧失类型信息
如果使用类型提示, 可能会像下面这样写, 但这样会丢失类型信息. list[Any] 表示可以接收任何类型的列表, 但 -> Any 意味着不知道返回的元素类型是什么, 这使得 mypy 等静态类型检测工具无法追踪类型, 降低了代码的可读性和安全性
from typing import Any def get_first_element(items: list[Any]) -> Any: return items[0] # 调用时, 类型检查工具无法得知 first_str 的类型 first_str = get_first_element(["hello", "world"]) 代码重复
如果为每种可能的类型都编写一个单独的函数, 则会导致代码重复
def get_first_int(items: list[int]) -> int: return items[0] def get_first_str(items: list[str]) -> str: return items[0] 通过引入 类型变量 (TypeVar) 来解决问题, 类型变量就像一个占位符, 代表在未来某时刻会被具体指定的类型
from typing import TypeVar T = TypeVar("T") def get_first_element(items: list[T]) -> T: return items[0] # 现在, 类型检查工具可以正确推断出类型 first_str: str = get_first_element(["hello", "world"]) first_int: int = get_first_element([1, 2, 3]) T = TypeVar('T') 定义了一个名为 T 的类型变量, 这里 T 只是一个约定俗成的名字, 也可以使用其他字母 items: list[T] 表示 items 是一个列表, 其内部元素类型是 T -> T: 返回类型也是 T 当使用 ["hello", "world"] 调用函数时, 静态类型检查器会推断出 T 是 str, 返回类型为 str 当使用 [1, 2, 3] 调用函数时, T 被推断为 int 注意: 这个函数假设列表非空, 如果传入空列表会抛出 IndexError
...