1. typing 模块 #
typing 模块是 Python 内置的类型提示工具,帮助我们显式标注函数与变量的类型,便于阅读、调试与静态检查。
2. 导入 typing 模块 #
开始使用前先掌握如何导入常用的类型别名或整个模块。
# 说明:从 typing 模块导入常见类型别名
from typing import List, Dict, Tuple, Set, Optional, Union, Any, Callable
# 说明:也可以整体导入 typing 模块
import typing3. 基本类型提示 #
这一部分先介绍最常见的标注方式,涵盖标量类型与容器类型。
3.1. 简单类型 #
用于标注函数参数与返回值的基础类型:字符串、整数、浮点与布尔值。
# 说明:定义问候函数,参数与返回值均为字符串
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:
return number % 2 == 0
# 说明:脚本入口,演示上述函数的返回值类型
if __name__ == "__main__":
result: str = greet("Alice")
area: float = calculate_area(5.0)
check: bool = is_even(10)
print(result, area, check)3.2. 容器类型 #
当函数需要处理列表、字典、元组或集合时,应同时标注元素类型以便阅读。
# 说明:导入容器类型别名
from typing import List, Dict, Tuple, Set
# 说明:定义函数,输入整数列表,返回缩放后的浮点列表
def process_numbers(numbers: List[int]) -> List[float]:
return [x * 1.5 for x in numbers]
# 说明:定义函数,返回姓名到分数的映射
def get_student_grades() -> Dict[str, int]:
return {"Alice": 95, "Bob": 87, "Charlie": 92}
# 说明:定义函数,返回经纬度坐标的元组
def get_coordinates() -> Tuple[float, float]:
return (40.7128, -74.0060)
# 说明:定义函数,接收字符串列表并返回唯一元素集合
def get_unique_items(items: List[str]) -> Set[str]:
return set(items)
# 说明:脚本入口,调用各容器函数
if __name__ == "__main__":
numbers: List[int] = [1, 2, 3, 4, 5]
grades: Dict[str, int] = get_student_grades()
coordinates: Tuple[float, float] = get_coordinates()
unique: Set[str] = get_unique_items(["a", "b", "a", "c"])
print(process_numbers(numbers))
print(grades)
print(coordinates)
print(unique)4. 高级类型提示 #
实际业务中参数可能允许多种类型或可为空,需要更灵活的注解写法。
4.1. Optional 类型 #
当返回值可能为具体类型或 None 时,使用 Optional[T] 更易读。
# 说明:导入 Optional 用于表示“可能为 None”
from typing import Optional
# 说明:根据用户 ID 返回姓名,若不存在则返回 None
def find_user(user_id: int) -> Optional[str]:
users = {1: "Alice", 2: "Bob"}
return users.get(user_id)
# 说明:Python 3.10+ 可用联合类型语法表示相同含义
def find_user_v2(user_id: int) -> str | None:
users = {1: "Alice", 2: "Bob"}
return users.get(user_id)
# 说明:脚本入口,演示如何安全地处理 Optional
if __name__ == "__main__":
user: Optional[str] = find_user(1)
if user is not None:
print(f"Found user: {user}")
else:
print("User not found")4.2. Union 类型 #
Union 表示“可以是多种类型之一”,Python 3.10+ 也能用 | 简写。
# 说明:导入 Union 来表示多种可能的输入类型
from typing import Union
# 说明:接受整数、浮点或字符串,统一转换为字符串
def process_value(value: Union[int, float, str]) -> str:
return str(value)
# 说明:Python 3.10+ 可使用更直观的管道写法
def process_value_v2(value: int | float | str) -> str:
return str(value)
# 说明:脚本入口,演示不同输入类型的结果
if __name__ == "__main__":
result1: str = process_value(42)
result2: str = process_value(3.14)
result3: str = process_value("hello")
print(result1, result2, result3)4.3. Any 类型 #
Any 会跳过静态检查,应谨慎使用,仅在没有更好选择时使用。
# 说明:导入 Any,表示“接受任意类型”
from typing import Any
# 说明:该函数既不约束输入也不约束输出,静态检查无法帮忙
def process_anything(data: Any) -> Any:
return data
# 说明:脚本入口,展示 Any 会原样返回各种类型
if __name__ == "__main__":
result1: int = process_anything(10)
result2: str = process_anything("text")
result3: list = process_anything([1, 2, 3])
print(result1, result2, result3)4.4. Callable 类型 #
用于描述“函数作为参数或返回值”的高阶函数场景。
# 说明:导入 Callable,用于描述函数签名
from typing import Callable, List
# 说明:接收一个加工函数,对整数列表逐个应用
def apply_operation(numbers: List[int], operation: Callable[[int], int]) -> List[int]:
return [operation(x) for x in numbers]
# 说明:返回一个新的函数,内部携带乘数
def multiplier(factor: int) -> Callable[[int], int]:
def multiply(x: int) -> int:
return x * factor
return multiply
# 说明:脚本入口,展示 lambda 与闭包的用法
if __name__ == "__main__":
numbers = [1, 2, 3, 4]
squared = apply_operation(numbers, lambda x: x ** 2)
double_func = multiplier(2)
doubled = apply_operation(numbers, double_func)
print(squared)
print(doubled)5. 泛型和类型变量 #
使用类型变量可以让一个函数或类同时适配多种类型,同时保持类型安全。
5.1. TypeVar #
TypeVar 声明一个“类型占位符”,调用时再推断具体类型。
# 说明:导入 TypeVar 与 Sequence 以声明类型变量
from typing import List, Sequence, Tuple, TypeVar
# 说明:声明两个类型变量,分别表示不同的占位类型
T = TypeVar('T')
U = TypeVar('U')
# 说明:函数返回序列的第一个元素,类型与输入保持一致
def first_element(seq: Sequence[T]) -> T:
return seq[0]
# 说明:函数交换元组中的两个元素,返回的顺序反转
def swap_pair(pair: Tuple[T, U]) -> Tuple[U, T]:
a, b = pair
return b, a
# 说明:脚本入口,演示 TypeVar 如何保持类型一致性
if __name__ == "__main__":
num_list: List[int] = [1, 2, 3]
first_num: int = first_element(num_list)
str_list: List[str] = ["a", "b", "c"]
first_str: str = first_element(str_list)
swapped: Tuple[str, int] = swap_pair((10, "hello"))
print(first_num, first_str, swapped)5.2. 泛型类 #
配合 Generic[T] 可以编写一次代码,支持多种数据类型的容器或工具类。
# 说明:导入 Generic 以构建泛型类
from typing import Generic, List, TypeVar
# 说明:声明类型变量 T,用于表示栈中元素的类型
T = TypeVar('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()
# 说明:判断栈是否为空
def is_empty(self) -> bool:
return len(self.items) == 0
# 说明:脚本入口,演示同一泛型类如何适配不同类型
if __name__ == "__main__":
int_stack: Stack[int] = Stack()
int_stack.push(1)
int_stack.push(2)
value: int = int_stack.pop()
str_stack: Stack[str] = Stack()
str_stack.push("hello")
text: str = str_stack.pop()
print(value, text, int_stack.is_empty())6. 更复杂的类型 #
Literal、Final 与 NewType 可进一步约束取值、声明常量或创建语义更明确的新类型。
6.1. Literal 类型 #
约束参数只能取某几个固定字面值,常用于配置或状态。
# 说明:导入 Literal,用来限定传入的字面值
from typing import Literal
# 说明:该函数只接受正态/停用/待定三个状态
def set_status(status: Literal["active", "inactive", "pending"]) -> None:
print(f"Status set to: {status}")
# 说明:脚本入口,演示合法与非法的调用方式
if __name__ == "__main__":
set_status("active") # 正确
# set_status("invalid") # IDE 会提示错误6.2. Final 类型 #
用于声明常量或不可被子类覆盖的属性,帮助避免误改。
# 说明:导入 Final,用于声明不可变常量
from typing import Final
# 说明:定义两个模块级常量
MAX_SIZE: Final[int] = 100
API_URL: Final[str] = "https://api.example.com"
# 说明:在类中同样可以使用 Final 锁定属性
class Config:
TIMEOUT: Final[int] = 30
# 说明:脚本入口,读取常量值
if __name__ == "__main__":
print(MAX_SIZE)
print(Config.TIMEOUT)6.3. NewType #
通过为基础类型建立别名,增强类型区分度,减少误用。
# 说明:导入 NewType,用于创建语义化的别名类型
from typing import NewType
# 说明:创建用户 ID 与邮箱类型,底层仍为 int 和 str
UserId = NewType('UserId', int)
Email = NewType('Email', str)
# 说明:函数签名使用自定义类型,避免误传
def get_user_name(user_id: UserId) -> str:
return f"User_{user_id}"
# 说明:发送邮件函数,要求邮箱类型更安全
def send_email(address: Email, message: str) -> None:
print(f"Sending to {address}: {message}")
# 说明:脚本入口,展示正确与错误的调用方式
if __name__ == "__main__":
user_id: UserId = UserId(12345)
email: Email = Email("user@example.com")
get_user_name(user_id) # 正确
send_email(email, "Hello") # 正确
# get_user_name(12345) # IDE 可能会警告
# send_email("user@example.com", "Hello") # IDE 可能会警告7. 实际应用示例 #
以下示例展示类型提示在真实业务中的写法,方便迁移到自己的项目。
7.1 示例 1:数据处理函数 #
使用 List、Dict、Optional 与 Tuple 表达复杂返回值与可选参数。
# 说明:导入所需的容器类型别名
from typing import Dict, List, Optional, Tuple
# 说明:根据可选过滤条件筛选用户,并返回结果列表与数量
def process_user_data(
users: List[Dict[str, str]],
filters: Optional[Dict[str, str]] = None
) -> Tuple[List[Dict[str, str]], int]:
if filters is None:
filters = {}
filtered_users = [
user for user in users
if all(user.get(key) == value for key, value in filters.items())
]
return filtered_users, len(filtered_users)
# 说明:脚本入口,传入示例数据并打印筛选结果
if __name__ == "__main__":
users_data = [
{"name": "Alice", "role": "admin", "status": "active"},
{"name": "Bob", "role": "user", "status": "inactive"},
{"name": "Charlie", "role": "admin", "status": "active"}
]
filtered, count = process_user_data(users_data, {"role": "admin"})
print(f"Found {count} admin users: {filtered}")7.2 示例 2:回调系统 #
借助 Callable 与 Any 描述事件回调签名,便于 IDE 发现不匹配。
# 说明:导入 Callable、List 与 Any 构建事件系统
from typing import Any, Callable, List
# 说明:事件处理类,内部维护回调函数列表
class EventHandler:
def __init__(self) -> None:
self._callbacks: List[Callable[[Any], None]] = []
# 说明:注册回调,将函数追加到列表
def register_callback(self, callback: Callable[[Any], None]) -> None:
self._callbacks.append(callback)
# 说明:触发事件,顺序调用所有已注册回调
def trigger_event(self, data: Any) -> None:
for callback in self._callbacks:
callback(data)
# 说明:打印事件数据的回调
def log_callback(data: Any) -> None:
print(f"Event received: {data}")
# 说明:处理字符串数据的回调,示例包含类型检查
def process_callback(data: Any) -> None:
if isinstance(data, str):
print(f"Processing string: {data.upper()}")
# 说明:脚本入口,注册并触发事件
if __name__ == "__main__":
handler = EventHandler()
handler.register_callback(log_callback)
handler.register_callback(process_callback)
handler.trigger_event("Hello, World!")8. Python 3.9+ 的新语法 #
在 Python 3.9 及以上版本,可直接使用内置泛型语法(如 list[int])令代码更简洁。
Python 3.9 开始,许多 typing 功能有了更简洁的语法:
# 说明:旧写法需要从 typing 导入 List、Dict 等
from typing import Dict, List
# 说明:对比旧写法与 3.9+ 新语法
def process_data_old(items: List[int]) -> Dict[str, float]:
return {str(item): float(item) for item in items}
# 说明:使用 3.9+ 新语法的写法
def process_data(items: list[int]) -> dict[str, float]:
return {str(item): float(item) for item in items}
# 说明:查找集合或列表中的首个元素,返回可选字符串
def find_item(collection: list[str] | set[str]) -> str | None:
if collection:
return collection[0] if isinstance(collection, list) else next(iter(collection))
return None
# 说明:脚本入口,展示新旧写法效果一致
if __name__ == "__main__":
data_old = process_data_old([1, 2, 3])
data_new = process_data([1, 2, 3])
result: str | None = find_item(["a", "b", "c"])
print(data_old, data_new, result)9. 总结 #
适度添加类型提示能显著提升代码可维护性,结合静态检查效果更佳。
typing 模块的主要优势:
- 提高代码可读性:明确函数参数和返回值的类型
- 更好的 IDE 支持:代码补全、错误检查、重构
- 早期错误检测:在运行前发现类型相关错误
- 便于维护:大型项目中类型提示特别有用
- 文档作用:作为代码的补充文档