环企首页
Python typing模块详解
typing 模块是 Python 中用于类型提示(Type Hints)的标准库,它允许你在代码中标注变量、函数参数和返回值的类型。这极大地提升了代码的可读性、可维护性,并为 IDE 和静态检查工具提供了支持。
1. 为什么需要类型提示?
没有类型提示(容易出错)
def add(a, b):
return a + b
result = add("hello", "world") # 返回 "helloworld",可能不是期望的行为
有类型提示(更清晰)
def add(a: int, b: int) -> int:
return a + b
# IDE 会提示你传递字符串可能有问题
result = add(5, 3) # 正确使用
2. 基础类型
from typing import List, Dict, Tuple, Set
# 基础类型
name: str = "Alice"
age: int = 25
price: float = 19.99
is_active: bool = True
# 集合类型
names: List[str] = ["Alice", "Bob"] # 字符串列表
scores: Dict[str, int] = {"math": 95} # 字符串→整数映射
point: Tuple[int, int] = (10, 20) # 两个整数的元组
tags: Set[str] = {"python", "coding"} # 字符串集合
3. 函数注解
def greet(name: str, age: int = 18) -> str:
"""返回问候语"""
return f"{name} 今年 {age} 岁"
def process_data(data: List[int]) -> Dict[str, float]:
"""处理数据并返回结果"""
return {"average": sum(data) / len(data)}
# 无返回值
def log_message(msg: str) -> None:
print(f"[LOG] {msg}")
4. 可选类型和联合类型
Optional:可能为 None
from typing import Optional
def find_user(user_id: int) -> Optional[str]:
"""返回用户名,如果不存在则返回 None"""
if user_id == 1:
return "Alice"
return None
# Python 3.10+ 可以写成 str | None
def get_config(key: str) -> str | None:
return os.getenv(key)
Union:多种可能的类型
from typing import Union
# Python 3.10+ 推荐使用 | 语法
def process(value: Union[int, str]) -> str: # 旧语法
return str(value)
# 新语法(Python 3.10+)
def process(value: int | str) -> str:
return str(value)
# 多种类型
def convert(data: int | float | str) -> float:
return float(data)
5. 高级类型
Any:任意类型(绕过类型检查)
from typing import Any
def flexible_func(data: Any) -> Any:
"""可以接受和返回任何类型"""
return data
# 不推荐过度使用,会失去类型检查的好处
TypeVar:泛型
from typing import TypeVar, List
T = TypeVar('T') # 类型变量
def first_element(items: List[T]) -> T:
"""返回列表的第一个元素,类型与列表元素一致"""
return items[0]
# 使用时自动推断类型
result1 = first_element([1, 2, 3]) # result1 被推断为 int
result2 = first_element(["a", "b"]) # result2 被推断为 str
Callable:函数类型
from typing import Callable
def apply_operation(x: int, y: int, operation: Callable[[int, int], int]) -> int:
"""应用一个二元运算函数"""
return operation(x, y)
# 使用
result = apply_operation(5, 3, lambda a, b: a + b) # 8
result = apply_operation(5, 3, lambda a, b: a * b) # 15
6. 特殊类型
Literal:字面量类型(Python 3.8+)
from typing import Literal
def set_mode(mode: Literal['read', 'write', 'append']) -> None:
"""mode 只能是 'read'、'write' 或 'append'"""
print(f"Mode set to {mode}")
set_mode('read') # 正确
# set_mode('delete') # 类型检查器会报错
TypedDict:字典的结构定义
from typing import TypedDict
class User(TypedDict):
name: str
age: int
email: str
# 使用时,IDE 会提供字段提示
user: User = {
"name": "Alice",
"age": 25,
"email": "alice@example.com"
}
print(user["name"]) # IDE 知道这是一个字符串
Protocol:结构性子类型(Python 3.8+,又名静态鸭子类型)
from typing import Protocol
class Drawable(Protocol):
def draw(self) -> None: ...
def render(obj: Drawable) -> None:
obj.draw()
class Circle:
def draw(self) -> None:
print("绘制圆形")
class Square:
def draw(self) -> None:
print("绘制正方形")
render(Circle()) # 有效,因为 Circle 实现了 draw 方法
render(Square()) # 有效
7. 新旧语法对比
| 功能 | Python < 3.9 | Python 3.9+ | Python 3.10+ |
|---|---|---|---|
| 列表 | List[int] |
list[int] |
list[int] |
| 字典 | Dict[str, int] |
dict[str, int] |
dict[str, int] |
| 元组 | Tuple[int, str] |
tuple[int, str] |
tuple[int, str] |
| 可选 | Optional[str] |
Optional[str] |
str | None |
| 联合 | Union[int, str] |
Union[int, str] |
int | str |
建议:如果你的 Python 版本 >= 3.9,优先使用内置类型(list、dict)而非 typing 中的大写版本;如果 >= 3.10,优先使用 | 语法而非 Union 和 Optional。
8. 实际应用示例
数据模型
from typing import List, Dict, Optional
from dataclasses import dataclass
@dataclass
class Address:
street: str
city: str
zipcode: str
@dataclass
class User:
id: int
name: str
email: str
address: Optional[Address] = None
tags: List[str] = None
API 客户端
import requests
from typing import Dict, Any, Optional
class APIClient:
def __init__(self, base_url: str, api_key: str) -> None:
self.base_url = base_url
self.api_key = api_key
def get(self, endpoint: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
response = requests.get(
f"{self.base_url}/{endpoint}",
params=params,
headers={"Authorization": f"Bearer {self.api_key}"}
)
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,
headers={"Authorization": f"Bearer {self.api_key}"}
)
return response.json()
函数重载(通过类型提示)
from typing import overload, Union
@overload
def process(data: int) -> int:
...
@overload
def process(data: str) -> str:
...
def process(data: Union[int, str]) -> Union[int, str]:
if isinstance(data, int):
return data * 2
else:
return data.upper()
9. 类型检查工具
类型提示本身不会在运行时强制检查,需要借助工具:
| 工具 | 说明 |
|---|---|
| mypy | 最流行的静态类型检查器 |
| pylint | 代码检查工具,支持类型提示 |
| PyCharm | IDE 内置类型检查 |
| VS Code | Pyright / Pylance 扩展 |
使用 mypy
# 安装
pip install mypy
# 运行检查
mypy your_script.py
# 忽略缺失的库类型
mypy --ignore-missing-imports your_script.py
10. 类型别名
from typing import List, Dict
# 定义类型别名
UserId = int
UserData = Dict[str, str]
UserList = List[UserId]
def get_users() -> UserList:
return [1, 2, 3]
def process_user(user_id: UserId, data: UserData) -> None:
print(f"Processing user {user_id}: {data}")
11. 运行时访问类型信息
from typing import get_type_hints
def greet(name: str, age: int = 18) -> str:
return f"{name} is {age} years old"
# 获取函数的类型提示
hints = get_type_hints(greet)
print(hints) # {'name': , 'age': , 'return': }
12. 总结
| 要点 | 说明 |
|---|---|
| 核心价值 | 提高代码可读性、支持 IDE 智能提示、帮助提前发现错误 |
| 运行时 | 类型提示不会影响运行效率,只是辅助工具 |
| 静态检查 | 配合 mypy、Pyright 等工具实现真正的类型检查 |
| 最佳实践 | 公共 API 必须写类型提示;内部函数也建议写 |
| 版本迁移 | Python >= 3.9 使用内置容器类型;>= 3.10 使用 | 语法 |
类型提示是现代 Python 开发的必备技能,它能让你的代码更加健壮、可维护,特别是在大型项目或团队协作中。