文章目录
一、用途
Python 的 typing
模块提供了类型提示的支持,这是 Python 3.5+ 引入的一项重要功能。主要用途包括:
- 代码可读性:明确函数参数和返回值的类型
- 静态类型检查:配合工具如 mypy 可以在运行前发现类型错误
- IDE支持:现代IDE可以利用类型提示提供更好的代码补全和错误检查
- 文档:作为代码文档的一部分,帮助其他开发者理解代码
二、基本功能
1. 基本类型提示
- name: str 表示参数name应为字符串类型
- -> str 表示函数返回字符串
- List[int] 表示元素为int的列表
from typing import List, Dict, Set, Tuple, Optional
def greet(name: str) -> str:
"""接受字符串name,返回问候字符串"""
return f"Hello, {name}"
def process_numbers(numbers: List[int]) -> float:
"""接受整数列表,返回平均值"""
return sum(numbers) / len(numbers)
2. 复合类型
List
:列表Dict
:字典Set
:集合Tuple
:元组
- List[type]: 特定类型元素的列表
- Dict[key_type, value_type]: 特定键值类型的字典
- Set[type]: 特定类型元素的集合
- Tuple[type1, type2, …]: 固定长度和类型的元组
def process_data(data: Dict[str, List[float]]) -> Set[str]:
"""处理字典数据,返回键的集合
Args:
data: 键为字符串,值为浮点数列表的字典
Returns:
包含所有键的集合
"""
return {k for k in data.keys()}
3. Optional 和 Union
- Optional[str] 等价于 Union[str, None],表示可能返回字符串或None
- Union[A, B] 表示可以是A或B类型,Union 更通用,可以表示任意类型的组合(两个或多个,不限于包含None)
from typing import Optional, Union
def find_user(user_id: int) -> Optional[str]:
"""根据用户ID查找用户名,可能返回None
Args:
user_id: 用户ID
Returns:
用户名或None(如果用户不存在)
"""
...
def parse_input(input: Union[str, bytes]) -> str:
"""解析字符串或字节输入,返回字符串
Args:
input: 可以是字符串或字节数据
Returns:
解码后的字符串
"""
...
4. Any 类型
- Any 类型表示完全动态类型,关闭类型检查
- 应谨慎使用,过度使用会削弱类型提示的价值
from typing import Any
def flexible_function(arg: Any) -> Any:
"""完全灵活的函数,接受和返回任意类型
Args:
arg: 任意类型的参数
Returns:
任意类型的返回值
"""
return arg
三、高级功能
1. TypeVar 泛型
- 泛型允许创建可处理多种类型但保持类型一致性的函数
- TypeVar 定义的T可以是任何类型,但输入和输出类型会关联
from typing import TypeVar, List
T = TypeVar('T') # 声明泛型类型变量
这里的 T 是一个类型变量,它可以代表任何类型,但在单个函数调用或类实例中,它的类型是保持一致的。
def first_element(lst: List[T]) -> T:
"""获取列表的第一个元素,保持类型一致性
Args:
lst: 任意类型的列表
Returns:
与列表元素类型相同的第一个元素
"""
return lst[0]
names: List[str] = ["Alice", "Bob", "Charlie"]
first_name = first_element(names) # 类型检查器知道 first_name 是 str
numbers: List[int] = [1, 2, 3]
first_num = first_element(numbers) # 类型检查器知道 first_num 是 int
说明
- 参数是一个元素类型为 T 的列表
- 返回值也是类型 T
- 在单次调用中,T 会被具体化为同一类型
2. Callable 函数类型
Callable 是 Python 类型注解(type hints)中的一个特殊类型,用于表示"可调用对象",也就是可以被调用的东西(比如函数、方法、实现了 call 方法的类等)。
- Callable[[参数类型,…], 返回类型] 描述函数类型
- 第一个列表是参数类型,最后一个元素是返回类型
from typing import Callable
def apply_func(func: Callable[[int, int], int], x: int, y: int) -> int:
"""应用一个接收两个int参数并返回int的函数
Args:
func: 可调用对象,接受两个int返回int
x: 第一个参数
y: 第二个参数
Returns:
func的执行结果
"""
return func(x, y)
3. Literal 字面量类型
Literal 用于限制参数只能是特定的字面量值(具体的值),而不是任意满足类型的值。
- 限制参数只能是特定的字面量值
- 有助于捕获拼写错误和无效值
from typing import Literal
def set_direction(direction: Literal["left", "right", "up", "down"]) -> None:
"""设置方向,只能是特定字符串值
Args:
direction: 必须是"left", "right", "up"或"down"之一
"""
...
说明
限制 direction 只能是这四个字符串之一
类似枚举的效果,但不需要定义枚举类
IDE 会根据提示自动补全可用值
4. Final 常量
Final 用于标记"不应被修改"的变量,相当于其他语言中的 const 或 final。
- 标记变量为"最终",表示不应被重新赋值
- 有助于防止意外修改重要常量
from typing import Final
MAX_SIZE: Final = 9000 # 定义不应被修改的常量
说明
告诉类型检查器这个变量不应该被重新赋值
向其他开发者表明这是常量
5. NewType 创建新类型
NewType 创建逻辑上的新类型,运行时仍是原始类型,但类型检查时会视为不同。
- 创建逻辑上的新类型,运行时仍是原始类型
- 提供更强的类型检查,防止普通int误用为UserId
from typing import NewType
UserId = NewType('UserId', int) # 创建UserId类型,本质仍是int但类型检查时会区分
def get_user_name(user_id: UserId) -> str:
"""通过UserId获取用户名
Args:
user_id: 用户ID,是特殊的int类型
Returns:
用户名
"""
...
说明
创建有语义的类型(如 UserId 不只是 int)
防止误用(不能直接把任意 int 当 UserId 用)
应用场景
区分不同的ID类型(用户ID vs 订单ID)
物理单位系统(米 vs 英尺)
领域特定值(Email地址 vs 普通字符串)
四、Python 3.9+ 的新语法
Python 3.9 开始,许多 typing 功能可以用内置类型直接表示:
# 代替 typing.List[int]
def process(items: list[int]) -> None:
"""处理整数列表"""
...
# 代替 typing.Dict[str, int]
def count_chars(s: str) -> dict[str, int]:
"""统计字符出现次数"""
...
# 代替 typing.Optional[int]
def find() -> int | None:
"""查找整数或返回None"""
...
- 更简洁的语法,功能与typing模块中的对应项相同
- | 操作符可用于替代Union类型
五、实际应用示例
from typing import TypedDict, Optional
class UserProfile(TypedDict):
"""用户配置文件类型定义"""
name: str # 必填字段
age: int # 必填字段
email: Optional[str] # 可选字段
def create_user_profile(name: str, age: int, email: str = None) -> UserProfile:
"""创建用户配置文件
Args:
name: 用户名
age: 年龄
email: 可选邮箱
Returns:
符合UserProfile类型的字典
"""
return {
"name": name,
"age": age,
"email": email
}
def send_welcome_email(profile: UserProfile) -> bool:
"""发送欢迎邮件
Args:
profile: 用户配置文件
Returns:
是否成功发送
"""
if profile["email"]:
print(f"Sending email to {profile['email']}")
return True
return False
TypedDict 创建有明确字段和类型的字典结构
结合Optional表示可选字段
提供完整的类型信息,便于IDE支持和文档生成
六、注意事项
- 运行时行为:类型提示不会影响Python的运行行为,Python仍然是动态类型语言
- 静态检查工具:需要使用mypy或pyright等工具进行静态类型检查
- 逐步采用:类型提示是可选的,可以逐步添加到现有代码中
- 性能影响:类型提示只在开发时使用,不会影响运行时性能
- 版本兼容:某些高级功能需要较新的Python版本支持