Python类型提示
typing 模块是 Python 在 PEP 484 中引入类型提示(Type Hints)后提供的官方标注支持库。其主要目的是配合外部工具进行静态代码分析(如使用 mypy、pyright 等进行类型检查)和辅助增强 IDE(如 VS Code、PyCharm)的代码补全和重构能力。
2. 基础使用
Section titled “2. 基础使用”- 普通使用示例:
def test(a: int, b: str) -> str: print(a, b) return "1000"- 自定义类型别名:
from typing import List
Vector = List[float]
def scale(scalar: float, vector: Vector) -> Vector: return [scalar * num for num in vector]
# 静态类型检查器通过:float 列表符合 Vector 类型别名定义new_vector = scale(2.0, [1.0, -4.2, 5.4])3. 常见类型分类
Section titled “3. 常见类型分类”3.1. 一、 集合与基本容器泛型 (Collections & Simple Types)
Section titled “3.1. 一、 集合与基本容器泛型 (Collections & Simple Types)”typing 类型 (Python < 3.9) | Python > = 3.9 原生支持语法 | 说明解释 |
|---|---|---|
List[int] | list[int] | 元素全为 int 类型的列表。 |
Dict[str, float] | dict[str, float] | 键为 str、值为 float 的字典映射。 |
Set[bool] | set[bool] | 元素全为 bool 类型的集合。 |
Tuple[str, int] | tuple[str, int] | 包含且仅包含一个 str 和一个 int 的固定长度元组。 |
Tuple[int, ...] | tuple[int, ...] | 元素全为 int 的未知任意长度元组。 |
3.2. 二、 关系与限定特殊类型 (Special Forms)
Section titled “3.2. 二、 关系与限定特殊类型 (Special Forms)”3.2.1. 联合类型 (Union Types)
Section titled “3.2.1. 联合类型 (Union Types)”声明变量的值可以兼容指定的多种不同类型之一。
typing 语法 (通用) | Python >= 3.10 原生语法 | 说明 |
|---|---|---|
Union[int, str] | `int | str` |
3.2.2. 可选类型 (Optional Type)
Section titled “3.2.2. 可选类型 (Optional Type)”声明变量的值可以为指定类型,或者为空(None)。
typing 语法 (通用) | Python >= 3.10 原生语法 | 说明 |
|---|---|---|
Optional[str] | `str | None` |
3.2.3. 任意类型 (Any)
Section titled “3.2.3. 任意类型 (Any)”代表不做类型限制。使用 Any 会导致静态类型检查器完全跳过针对该对象的语法校验。
from typing import Any
def process(data: Any) -> Any: # 静态检查器会忽略对 data 对象的检查 return data3.2.4. 可调用类型 (Callable)
Section titled “3.2.4. 可调用类型 (Callable)”用于给函数、方法或支持 __call__ 的对象声明函数签名类型。
from typing import Callable, List
# 接收一个 int 参数,返回一个 str 的函数类型Worker = Callable[[int], str]
def execute_task(func: Worker, value: int) -> str: return func(value)
# 接收任意参数,并返回一个 List [str] 的函数(参数列表使用 ... 占位)AnyParamFunc = Callable[..., List[str]]3.2.5. 类对象类型 (Type)
Section titled “3.2.5. 类对象类型 (Type)”用于表示 类定义本身(即类模板对象),而非该类的具体实例。
from typing import Type
class Base: passclass Derived(Base): pass
# 参数 class_obj 期望传入 Base 类本身或其派生类,而非 Base 的实例对象def create_instance(class_obj: Type[Base]) -> Base: return class_obj()
# 静态类型检查通过instance = create_instance(Derived)3.3. 三、 泛型与别名 (Generics)
Section titled “3.3. 三、 泛型与别名 (Generics)”3.3.1. 类型变量 (TypeVar)
Section titled “3.3.1. 类型变量 (TypeVar)”用于定义泛型结构中的占位符。
from typing import TypeVar, List
# T 表示未知的泛型占位符T = TypeVar('T')
def get_first_item(items: List[T]) -> T: """输入列表的元素类型与返回值类型在检查时保持完全一致""" return items[0]
# 支持约束范围的类型变量Number = TypeVar('Number', int, float) # 限制只能为 int 或 float 之一
def add_two(x: Number) -> Number: return x + 23.3.2. 类型别名 (Type Aliases)
Section titled “3.3.2. 类型别名 (Type Aliases)”# Python >= 3.12 推荐使用 type 关键字声明(更清晰)type Coordinate = dict[str, int | float]
def get_coord(c: Coordinate): pass3.4. 四、 高级实用校验工具
Section titled “3.4. 四、 高级实用校验工具”| 核心组件 | 主要功能说明 | 代码示例 |
|---|---|---|
NewType | 创建一个在语义上存在区分的独立类型。检查器会将其视为子类进行控制,防止误传。 | UserId = NewType('UserId', int) |
Literal | 限制变量只能被赋予指定的某些特定字面值。 | Color = Literal['red', 'green', 'blue'] |
TypedDict | 限制字典必须具备固定的键(Key)且键对应的 Value 满足特定类型。 | class User(TypedDict): name: str; age: int |
Protocol | 结构化子类型(支持静态的 Duck Typing)。实现该 Protocol 声明的方法即视为其子类,无需显式继承。 | class Runnable(Protocol): def run(self) -> None: ... |
Final | 声明变量、方法或类 不应被重新赋值、方法重写或子类继承。 | PI: Final[float] = 3.14159 |
NoReturn | 标注函数永远不会有 return 返回值(通常意味着函数必定会抛出异常或进入死循环)。 | def die() -> NoReturn: raise Exception() |
TYPE_CHECKING | 静态检查运行期为 True,但在真实 Python 解释运行期为 False 的常量,常用于防止循环导入。 | if TYPE_CHECKING: from . import heavy_module |
3.5. 五、 未来演进趋势 (Python 3.12+)
Section titled “3.5. 五、 未来演进趋势 (Python 3.12+)”Python 的类型系统正在变得更加简洁,大量原本需要从 typing 导出的功能已经内置为系统级关键字:
type关键字 (PEP 695):声明类型别名无需再依赖赋值式代码。- 泛型声明简化 (PEP 695):类定义中可以直接在类名后用
[T]占位,免去了声明Generic[T]的冗长逻辑:- 旧版:
T = TypeVar('T'); class Box(Generic[T]): ... - 新版:
class Box[T]: ...
- 旧版:
@override装饰器 (PEP 698):静态层级校验当前子类方法是否正确重写了父类方法。
3.5.1. 函数签名重载装饰器 @overload 综合实例
Section titled “3.5.1. 函数签名重载装饰器 @overload 综合实例”from typing import overload, Union, List, Any
# 1. 声明重载签名一:输入 int,返回 int@overloaddef process_data(data: int) -> int: ...
# 2. 声明重载签名二:输入 str,返回 List [str]@overloaddef process_data(data: str) -> List[str]: ...
# 3. 声明重载签名三:输入 List [Any],返回 str@overloaddef process_data(data: List[Any]) -> str: ...
# 4. 实现的函数本体:其参数与返回值应兼容所有的重载约束,但运行时以此实现为准def process_data(data: Union[int, str, List[Any]]) -> Union[int, List[str], str]: if isinstance(data, int): print("处理整数") return data * 2 elif isinstance(data, str): print("处理字符串") return [data.upper()] elif isinstance(data, list): print("处理列表") return ",".join(map(str, data)) else: raise TypeError("不支持的类型")
# 静态类型检查器(如 Mypy)进行校验:a: int = process_data(10) # 自动映射推断返回 intb: List[str] = process_data("test") # 自动映射推断返回 List [str]c: str = process_data([1, 2, "a"]) # 自动映射推断返回 str4. 拓展说明
Section titled “4. 拓展说明”4.1. ... (省略号/三点符) 的不同语境含义
Section titled “4.1. ... (省略号/三点符) 的不同语境含义”| 场景 | 语境说明 | 示例 |
|---|---|---|
| 类型提示 | 代表函数接受任意类型和数量的参数 | Callable[..., int] |
| 类型提示 | 代表元组可容纳任意个满足该类型的元素 | Tuple[int, ...] |
| 科学计算 | NumPy 数组中代表省略多维切片的前置索引 | array[..., 0] |
| 代码占位 | 代替 pass 声明尚未编写具体实现的代码块 | def func(): ... |
| 数据类 | dataclass 的 field 用作表示没有指定默认值 | field(default=...) |
4.2. | (竖线) 的不同语境含义
Section titled “4.2. | (竖线) 的不同语境含义”| 场景 | 语境说明 | 示例 |
|---|---|---|
| 逻辑运算 | 按位或运算 (Bitwise OR) | `x |
| 集合操作 | 两个 Set 集合合并求并集 | `set_a |
| 字典操作 | 两个 Dict 字典合并 (Python 3.9+) | `dict_a |
| 类型提示 | 联合类型联合 (Union) (Python 3.10+) | `int |