# 类型提示 Python 3.5+ 引入了类型提示(Type Hints),它能提高代码可读性,帮助 IDE 提供更好的支持,并能配合类型检查工具发现潜在错误。 ## 基础类型提示 ### 基本类型 ```python # 变量注解 name: str = "Alice" age: int = 30 height: float = 1.75 is_active: bool = True # 函数注解 def greet(name: str) -> str: return f"Hello, {name}!" # 可选参数 def greet_with_default(name: str = "World") -> str: return f"Hello, {name}!" ``` ### 容器类型 ```python from typing import List, Dict, Set, Tuple # Python 3.9+ 可以直接使用内置类型 names: list[str] = ["Alice", "Bob"] scores: dict[str, int] = {"Alice": 90, "Bob": 85} unique_ids: set[int] = {1, 2, 3} point: tuple[int, int] = (10, 20) # Python 3.8 及以下需要从 typing 导入 from typing import List, Dict, Set, Tuple names: List[str] = ["Alice", "Bob"] scores: Dict[str, int] = {"Alice": 90} # 可变长度元组 numbers: tuple[int, ...] = (1, 2, 3, 4, 5) # 嵌套类型 matrix: list[list[int]] = [[1, 2], [3, 4]] users: dict[str, dict[str, int]] = { "alice": {"age": 30, "score": 90} } ``` ## Optional 和 Union ```python from typing import Optional, Union # Optional[X] 等价于 Union[X, None] def find_user(user_id: int) -> Optional[str]: """可能返回 None""" users = {1: "Alice", 2: "Bob"} return users.get(user_id) # Union: 多个类型之一 def process(value: Union[int, str]) -> str: return str(value) # Python 3.10+ 可以使用 | 语法 def process_new(value: int | str) -> str: return str(value) def find_user_new(user_id: int) -> str | None: users = {1: "Alice", 2: "Bob"} return users.get(user_id) ``` ## Callable 和函数类型 ```python from typing import Callable # 函数类型:Callable[[参数类型...], 返回类型] def apply(func: Callable[[int], int], value: int) -> int: return func(value) def double(x: int) -> int: return x * 2 result = apply(double, 5) # 10 # 可变参数的 Callable from typing import Callable, Any def log_call(func: Callable[..., Any]) -> Callable[..., Any]: def wrapper(*args: Any, **kwargs: Any) -> Any: print(f"Calling {func.__name__}") return func(*args, **kwargs) return wrapper ``` ## 泛型 ### TypeVar ```python from typing import TypeVar, List, Sequence T = TypeVar('T') def first(items: Sequence[T]) -> T: """返回序列的第一个元素,保持类型信息""" return items[0] # 类型检查器知道返回类型 strings = ["a", "b", "c"] first_str: str = first(strings) # str numbers = [1, 2, 3] first_num: int = first(numbers) # int # 受限的 TypeVar Number = TypeVar('Number', int, float) def add(a: Number, b: Number) -> Number: return a + b # 绑定的 TypeVar from typing import TypeVar Comparable = TypeVar('Comparable', bound='Comparable') class Comparable: def __lt__(self, other: 'Comparable') -> bool: ... ``` ### Generic 类 ```python from typing import TypeVar, Generic, Optional 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 peek(self) -> Optional[T]: return self._items[-1] if self._items else None def is_empty(self) -> bool: return len(self._items) == 0 # 使用 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") ``` ## Protocol(结构化子类型) ```python from typing import Protocol, runtime_checkable class Drawable(Protocol): """定义接口:任何有 draw 方法的类型""" def draw(self) -> str: ... class Circle: def draw(self) -> str: return "Drawing circle" class Square: def draw(self) -> str: return "Drawing square" def render(shape: Drawable) -> None: print(shape.draw()) # Circle 和 Square 没有显式继承 Drawable # 但它们符合 Drawable 协议(鸭子类型) render(Circle()) # OK render(Square()) # OK # 运行时检查 @runtime_checkable class Closeable(Protocol): def close(self) -> None: ... class File: def close(self) -> None: pass print(isinstance(File(), Closeable)) # True ``` ## TypedDict ```python from typing import TypedDict, Required, NotRequired class UserDict(TypedDict): name: str age: int email: str # 所有键都是必需的 user: UserDict = { "name": "Alice", "age": 30, "email": "alice@example.com" } # Python 3.11+: 控制必需/可选 class UserDictNew(TypedDict): name: Required[str] age: Required[int] email: NotRequired[str] # 可选 # total=False 使所有键可选 class PartialUser(TypedDict, total=False): name: str age: int email: str ``` ## Literal 和 Final ```python from typing import Literal, Final # Literal: 限制具体值 def set_mode(mode: Literal["read", "write", "append"]) -> None: print(f"Mode: {mode}") set_mode("read") # OK # set_mode("delete") # 类型检查器报错 # Final: 不可重新赋值 MAX_CONNECTIONS: Final = 100 # MAX_CONNECTIONS = 200 # 类型检查器报错 # Final 类属性 class Config: DEBUG: Final[bool] = False # 子类不能覆盖 Final 属性 ``` ## 实用类型 ### Any、Never、NoReturn ```python from typing import Any, NoReturn, Never # Any: 任意类型(跳过类型检查) def process_anything(value: Any) -> Any: return value # NoReturn: 函数永不返回 def raise_error() -> NoReturn: raise RuntimeError("Error!") def infinite_loop() -> NoReturn: while True: pass # Never (Python 3.11+): 不可能的类型 def assert_never(value: Never) -> NoReturn: raise AssertionError(f"Unexpected value: {value}") ``` ### Self(Python 3.11+) ```python from typing import Self class Builder: def __init__(self) -> None: self._value = 0 def add(self, n: int) -> Self: self._value += n return self def multiply(self, n: int) -> Self: self._value *= n return self # 链式调用 result = Builder().add(5).multiply(2)._value ``` ### Annotated ```python from typing import Annotated # 附加元数据到类型 UserId = Annotated[int, "user ID"] PositiveInt = Annotated[int, "must be positive"] def get_user(user_id: UserId) -> str: return f"User {user_id}" # 常与验证库配合使用(如 Pydantic) from pydantic import BaseModel, Field class User(BaseModel): name: Annotated[str, Field(min_length=1, max_length=50)] age: Annotated[int, Field(ge=0, le=150)] ``` ## 类型检查工具 ### mypy ```bash # 安装 pip install mypy # 检查单个文件 mypy script.py # 检查整个项目 mypy src/ # 严格模式 mypy --strict src/ ``` ### 配置文件(mypy.ini 或 pyproject.toml) ```ini # mypy.ini [mypy] python_version = 3.10 warn_return_any = True warn_unused_ignores = True disallow_untyped_defs = True # 忽略特定模块 [mypy.plugins.external_lib.*] ignore_missing_imports = True ``` ### 内联忽略 ```python # 忽略特定行 x = some_untyped_function() # type: ignore # 忽略特定错误 x = some_function() # type: ignore[arg-type] # 揭示推断类型(调试用) reveal_type(x) # mypy 会输出推断的类型 ``` ## 最佳实践 ::::{grid} 1 :gutter: 2 :::{grid-item-card} 渐进式类型 1. **从公共 API 开始**:函数签名、类方法 2. **逐步添加**:不需要一次性完成所有类型注解 3. **使用 `py.typed` 标记**:表明包支持类型检查 ::: :::{grid-item-card} 常见模式 ```python # 返回 self 用于链式调用 from __future__ import annotations class Builder: def method(self) -> Builder: # 或使用 Self return self # 类型别名提高可读性 from typing import TypeAlias UserId: TypeAlias = int UserDict: TypeAlias = dict[str, Any] # 前向引用(类引用自身) class Node: def __init__(self, children: list['Node']) -> None: self.children = children ``` ::: :::{grid-item-card} 注意事项 1. **类型提示不影响运行时**(除非使用 `@runtime_checkable`) 2. **避免过度使用 `Any`**:失去类型检查意义 3. **使用 `from __future__ import annotations`**:延迟求值,支持前向引用 4. **保持一致性**:团队统一风格和严格程度 ::: ::::