Python 类型注解:typing 模块的详细使用
理解 Python 类型注解是Python 3.5引入的功能,允许开发者在代码中显式声明变量、函数参数和返回值的预期数据类型。
安装 Python 3.9及以上版本已内置typing模块,无需额外安装。
为什么需要类型注解
提高 代码可读性:类型注解让代码更容易理解,特别是对于大型项目或团队协作。
增强 IDE功能:支持现代IDE如PyCharm、VSCode等提供更好的代码补全、静态分析和错误检查。
辅助 静态类型检查:配合mypy等工具可以在不运行代码的情况下发现类型错误。
实现 文档自包含:类型注解作为文档的一部分,减少单独编写文档的需要。
typing 模块基础类型
基本类型注解
声明 变量类型:
name: str = "Alice"
age: int = 30
height: float = 5.6
is_student: bool = True
声明 函数参数和返回值类型:
def add(a: int, b: int) -> int:
return a + b
使用 类型别名提高可读性:
UserId = int
Username = str
def get_user_name(user_id: UserId) -> Username:
# 函数实现
pass
常用类型
查看 typing模块提供的常用类型:
| 类型 | 描述 | 示例 |
|---|---|---|
List |
列表类型 | List[int], List[str] |
Tuple |
元组类型 | Tuple[int, str, float] |
Dict |
字典类型 | Dict[str, int] |
Set |
集合类型 | Set[int] |
Optional |
可选类型 | Optional[int]等同于Union[int, None] |
Union |
联合类型 | Union[int, str] |
Any |
任意类型 | Any |
Callable |
可调用类型 | Callable[[int, int], int] |
容器类型注解
列表(List)
声明 单一类型列表:
from typing import List
numbers: List[int] = [1, 2, 3, 4, 5]
names: List[str] = ["Alice", "Bob", "Charlie"]
声明 嵌套列表:
matrix: List[List[int]] = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
元组(Tuple)
声明 固定长度和类型的元组:
from typing import Tuple
point: Tuple[int, int] = (3, 4)
person: Tuple[str, int, float] = ("Alice", 30, 5.6)
声明 不同长度元组:
# 可变长度元组
mixed: Tuple[str, ...] = ("a", "b", "c", "d", "e")
字典(Dict)
声明 键值对类型:
from typing import Dict
student_scores: Dict[str, int] = {
"Alice": 90,
"Bob": 85,
"Charlie": 92
}
# 嵌套字典
nested_dict: Dict[str, Dict[str, int]] = {
"class1": {"Alice": 90, "Bob": 85},
"class2": {"Charlie": 92, "David": 88}
}
集合(Set)
声明 集合类型:
from typing import Set
unique_numbers: Set[int] = {1, 2, 3, 4, 5}
unique_words: Set[str] = {"apple", "banana", "cherry"}
高级类型
可选类型(Optional)和联合类型(Union)
使用 Optional 表示可能为None的值:
from typing import Optional
def find_user(user_id: int) -> Optional[dict]:
# 查找用户,如果不存在返回None
pass
使用 Union 表示多种可能的类型:
from typing import Union
def process_data(data: Union[int, str]) -> str:
if isinstance(data, int):
return f"Number: {data}"
else:
return f"String: {data}"
注意 在Python 3.10及以上,可以使用 | 操作符替代 Union:
# Python 3.10+
def process_data(data: int | str) -> str:
# 函数实现
pass
可调用类型(Callable)
声明 函数作为参数或返回值:
from typing import Callable
def add(a: int, b: int) -> int:
return a + b
def apply_operation(x: int, y: int, operation: Callable[[int, int], int]) -> int:
return operation(x, y)
result = apply_operation(3, 4, add) # 结果为7
生成器类型(Iterator, Generator)
声明 迭代器和生成器类型:
from typing import Iterator, Generator
def count_up_to(n: int) -> Iterator[int]:
i = 1
while i <= n:
yield i
i += 1
def infinite_counter() -> Generator[int, None, None]:
i = 0
while True:
yield i
i += 1
类型变量(TypeVar)
声明 泛型函数中的类型变量:
from typing import TypeVar, List
T = TypeVar('T')
def first_element(items: List[T]) -> T:
return items[0]
# 使用示例
num = first_element([1, 2, 3]) # num类型为int
name = first_element(["Alice", "Bob"]) # name类型为str
约束类型变量
声明 有约束的类型变量:
from typing import TypeVar, Sequence
# T必须是Sequence的子类型
T = TypeVar('T', bound=Sequence[int])
def get_length(seq: T) -> int:
return len(seq)
# 使用示例
list_len = get_length([1, 2, 3]) # 有效
tuple_len = get_length((1, 2, 3)) # 有效
str_len = get_length("hello") # 有效,因为str是Sequence
dict_len = get_length({"a": 1}) # 无效,因为dict不是Sequence[int]
类型检查工具
使用 mypy进行静态类型检查:
# 安装mypy
pip install mypy
# 检查Python文件
mypy script.py
# 检查整个项目
mypy my_project/
配置 mypy配置文件(mypy.ini):
[mypy]
python_version = 3.9
warn_return_any = True
warn_unused_configs = True
disallow_untyped_defs = True
实际应用示例
数据模型类
创建 使用类型注解的数据模型:
from dataclasses import dataclass
from typing import List, Optional
@dataclass
class User:
id: int
name: str
email: str
age: Optional[int] = None
friends: List[int] = None
def __post_init__(self):
if self.friends is None:
self.friends = []
# 使用示例
user = User(id=1, name="Alice", email="alice@example.com")
API客户端
实现 带类型注解的API客户端:
from typing import Dict, Any, Optional
import requests
class APIClient:
def __init__(self, base_url: str):
self.base_url = base_url
def get(self, endpoint: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
response = requests.get(f"{self.base_url}{endpoint}", params=params)
response.raise_for_status()
return response.json()
def post(self, endpoint: str, data: Dict[str, Any]) -> Dict[str, Any]:
response = requests.post(f"{self.base_url}{endpoint}", json=data)
response.raise_for_status()
return response.json()
# 使用示例
client = APIClient("https://api.example.com")
user_data = client.get("/users/1")
数据处理管道
构建 使用类型注解的数据处理管道:
from typing import List, Callable, Any
def process_pipeline(data: List[Any], *processors: Callable[[List[Any]], List[Any]]) -> List[Any]:
result = data
for processor in processors:
result = processor(result)
return result
# 定义处理器函数
def filter_positive(numbers: List[int]) -> List[int]:
return [n for n in numbers if n > 0]
def double_numbers(numbers: List[int]) -> List[int]:
return [n * 2 for n in numbers]
# 使用示例
data = [-1, 2, -3, 4, 0, 5]
result = process_pipeline(data, filter_positive, double_numbers)
# 结果: [4, 8, 10]
性能考量
注意 类型注解本身不会影响运行时性能,因为Python是动态类型语言。
使用 from __future__ import annotations 在Python 3.7及以下版本中启用后向兼容的类型注解:
from __future__ import annotations
def func(a: int) -> str:
return str(a)
考虑 在性能关键代码中,可以使用类型注解结合@typing.runtime_checkable装饰器实现运行时类型检查:
from typing import Protocol, runtime_checkable
@runtime_checkable
class Drawable(Protocol):
def draw(self) -> None:
...
def draw_object(obj: Drawable) -> None:
obj.draw()
常见错误和最佳实践
避免 过度使用Any类型,这会失去类型检查的好处。
优先 使用具体类型而非Any:
# 不推荐
def process(data: Any) -> Any:
return str(data)
# 推荐
def process(data: Union[int, str]) -> str:
return str(data)
使用 类型别名提高代码可读性:
# 不推荐
def get_user(id: int) -> Dict[str, Union[int, str, float]]: ...
# 推荐
UserId = int
UserInfo = Dict[str, Union[int, str, float]]
def get_user(id: UserId) -> UserInfo: ...
利用 类型注解作为文档的一部分,但不要仅依赖类型注解提供完整文档。
考虑 使用第三方库如pydantic和dataclasses-json在需要序列化/反序列化时提供更高级的类型支持。

暂无评论,快来抢沙发吧!