1. typing 模块 #
typing是 Python 内置模块,用于给函数参数、返回值和变量添加类型注解。- 类型注解不会在运行时强制检查,主要作用是提升可读性、IDE 补全和静态分析(如 mypy、Pyright)。
- Python 3.9+ 可直接用
list[int]、dict[str, str]等内置写法,多数场景不必再从 typing 导入List、Dict。
1.1 导入方式 #
# Python 3.9+:一般只需导入高级类型
from typing import Optional, Callable
# 需要兼容旧版本或用到泛型时
from typing import TypeVar, Generic2. 基本类型提示 #
- 函数参数用
参数名: 类型标注,返回值用-> 类型标注。 - 变量也可标注类型,如
name: str = "Alice",帮助 IDE 推断和提示。 - 基础类型包括
str、int、float、bool,日常开发中最常用。 - 类型注解是"提示"而非约束,传错类型 Python 运行时不会报错,但静态检查工具会警告。
2.1 函数注解 #
# 定义问候函数,参数和返回值均为 str
def greet(name: str) -> str:
# 返回格式化问候语
return f"Hello, {name}"
# 定义计算圆面积的函数
def calculate_area(radius: float) -> float:
# 用近似 π 计算面积
return 3.14159 * radius ** 2
# 定义判断偶数的函数
def is_even(number: int) -> bool:
# 余数为 0 即为偶数
return number % 2 == 02.2 变量注解 #
# 声明字符串变量
name: str = "Alice"
# 声明整型变量
count: int = 0
# 声明字符串列表
items: list[str] = ["a", "b", "c"]3. 容器类型 #
- 容器类型需要同时标注"容器本身"和"元素类型",如
list[int]表示整数列表。 - Python 3.9+ 推荐用内置写法
list、dict、tuple、set,比typing.List更简洁。 - 字典标注为
dict[键类型, 值类型],元组标注为tuple[类型1, 类型2, ...]。 - 嵌套容器如
dict[str, list[int]]在数据处理、API 接口中很常见。
# 接收整数列表,返回浮点数列表
def process_numbers(numbers: list[int]) -> list[float]:
# 每个元素乘以 1.5
return [x * 1.5 for x in numbers]
# 返回姓名到成绩的映射
def get_student_grades() -> dict[str, int]:
return {"Alice": 95, "Bob": 87}
# 返回二维坐标元组
def get_coordinates() -> tuple[float, float]:
return (40.7128, -74.0060)
# 字符串列表去重为集合
def get_unique_items(items: list[str]) -> set[str]:
return set(items)4. 高级类型提示 #
Optional[T]或T | None表示值可以是某类型或None,查找、解析等可能失败的场景必用。Union[A, B]或A | B表示多种类型之一,如参数既接受int也接受str。Callable描述函数类型,常用于回调函数、装饰器、高阶函数参数。Any表示任意类型,会跳过静态检查,应尽量避免,仅在确实无法确定类型时使用。
4.1 Optional(可能为 None) #
# 按 ID 查找用户,找不到返回 None
def find_user(user_id: int) -> str | None:
# 模拟用户数据字典
users = {1: "Alice", 2: "Bob"}
# get 在键不存在时返回 None
return users.get(user_id)
# 调用查找函数
user = find_user(1)
# 判空后再使用,避免 None 错误
if user is not None:
print(f"Found: {user}")Optional[str] 等价于 str | None(Python 3.10+ 推荐后者)。
4.2 Union(多种类型之一) #
# 接受 int、float 或 str,统一转为字符串
def process_value(value: int | float | str) -> str:
return str(value)
# 传入整数,合法
process_value(42)
# 传入字符串,同样合法
process_value("hello")4.3 Callable(函数类型) #
# 导入 Callable 类型
from typing import Callable
# 对列表每个元素应用传入的一元函数
def apply_operation(
numbers: list[int],
operation: Callable[[int], int]
) -> list[int]:
return [operation(x) for x in numbers]
# 用 lambda 对每个数求平方
apply_operation([1, 2, 3], lambda x: x ** 2)4.4 Literal(固定字面值) #
限制参数只能是几个固定字符串,常用于状态、模式等配置:
# 导入 Literal 类型
from typing import Literal
# 限制 status 只能是三个固定字符串之一
def set_status(status: Literal["active", "inactive", "pending"]) -> None:
print(f"Status: {status}")
# 传入合法字面值
set_status("active")
# 传入非法值时,静态检查会警告
# set_status("invalid")5. 泛型简介 #
TypeVar声明类型变量,让函数在保持类型安全的同时适配多种具体类型。Generic[T]用于编写泛型类,如通用容器、缓存类,库和框架开发中较常见。
5.1 类型变量 #
TypeVar是 Python 的typing模块中用于定义 泛型类型变量 的工具。它允许你编写可以接受多种类型、并保持类型之间关联性的通用代码,同时让静态类型检查器能够正确推断和验证类型。TypeVar('T')创建了一个 无约束的类型变量,它可以是 任意类型。在泛型函数或类中,这个变量会在使用时被具体的类型替代。- 例如,假如我们希望编写一个返回列表首元素的函数:用
TypeVar('T')声明一个泛型类型变量T,参数类型list[T]代表"元素为任意同种类型T的列表",返回值也为T。这样,无论传入的是list[int]、list[str]还是其他类型的列表,类型检查器都能推断出具体类型并校验安全。这样做比单纯用list更严格和智能,避免意外的类型错误。 - 最常见的泛型场景包括容器类(如列表、字典、栈等)和通用工具函数(如映射、过滤、排序等),
TypeVar让你的代码更灵活,也让类型系统更智能地辅助发现程序中的潜在错误。
# 导入 TypeVar
from typing import TypeVar
# 声明泛型类型变量 T
# 左边的 T:是一个 Python 变量名,用于在代码中引用这个类型变量。
# 右边的 'T'(字符串):是类型变量的 内部名称,主要用于 调试输出、错误消息、类型签名 的显示。
T = TypeVar('T')
# 返回列表首元素,类型与元素一致
def first_element(items: list[T]) -> T:
return items[0]
# T 被推断为 int
first_element([1, 2, 3])
# T 被推断为 str
first_element(["a", "b"])5.2 泛型类 #
Generic是typing模块中用于定义 泛型类 的基类。它允许你创建一个类,其内部某些类型可以延迟到实例化时指定,从而实现类型安全且可复用的数据结构。- 常见容器类型如列表、字典、栈等都可以抽象为泛型类。
- 例如,下方的 Stack 类就是一个通用的栈结构:你初始化时不指定元素类型,只有在用实际类型参数创建实例时类型变量
T才会被具体化。 - 泛型类的好处是可以让类型检查器根据你的实际用途自动推断出类型,提高代码的灵活性和安全性。例如:
Stack[int]()只能存放整数,Stack[str]()只能存放字符串,如果误操作就会提示类型错误。这为编写通用库和组件带来了极大便利。
下例演示了如何自定义一个支持任意元素类型的泛型栈:
# 导入泛型基类和类型变量
from typing import Generic, TypeVar
# 声明类型变量 T
T = TypeVar('T')
# 定义泛型栈,T 表示元素类型
class Stack(Generic[T]):
# 初始化空列表作为栈
def __init__(self) -> None:
self.items: list[T] = []
# 压入元素
def push(self, item: T) -> None:
self.items.append(item)
# 弹出栈顶元素
def pop(self) -> T:
return self.items.pop()6. 实际应用示例 #
- 下面是一个典型的数据处理函数,综合使用了容器类型、Optional 默认参数和元组返回值。
- 这种写法在 Web 后端、数据脚本中非常常见,可直接作为项目函数的注解模板。
- 类型注解让函数签名自解释,协作者无需阅读函数体就能了解入参和返回结构。
- 配合 IDE 或 mypy 可在提交前发现类型不匹配的错误。
# 按条件筛选用户,返回结果和数量
def filter_users(
users: list[dict[str, str]],
filters: dict[str, str] = {}
) -> tuple[list[dict[str, str]], int]:
"""按条件筛选用户,返回筛选结果和数量。"""
# 保留满足所有筛选条件的用户
result = [
user for user in users
if all(user.get(k) == v for k, v in filters.items())
]
# 返回结果列表和匹配数量
return result, len(result)
# 构造测试用户数据
users = [
{"name": "Alice", "role": "admin"},
{"name": "Bob", "role": "user"},
{"name": "Charlie", "role": "admin"},
]
# 筛选 role 为 admin 的用户
filtered, count = filter_users(users, {"role": "admin"})
print(f"找到 {count} 个管理员: {filtered}")7. 总结 #
- 类型注解是提升代码质量和团队协作效率的低成本手段,建议在新项目中养成习惯。
- 日常开发重点掌握:基础类型、容器类型(
list[int]等)、Optional/|联合类型、Callable。 - 类型注解不替代单元测试,但能在编码阶段就发现大量低级错误。
7.1 常用写法速查 #
# 基础函数注解(函数体省略)
from typing import Callable
def fn(name: str, age: int) -> bool: ...
# 空字符串列表
items: list[str] = []
# 空字符串到整数的字典
mapping: dict[str, int] = {}
# 二维浮点坐标
point: tuple[float, float] = (0.0, 0.0)
# 可能返回 None 的查找函数
def find(id: int) -> str | None: ...
# 接受 int 或 str 的解析函数
def parse(value: int | str) -> str: ...
# 接受字符串回调的函数
def run(callback: Callable[[str], None]) -> None: ...7.2 最佳实践 #
- 给公共 API(模块导出函数、类方法)添加类型注解,内部私有函数可按需添加
- 优先用具体类型,避免滥用
Any - 新项目用
list[int]、str | None等现代语法 - 配合 IDE 类型检查获得最大收益