跳转至

05 - 类型注解与工具

学习时间: 1小时 重要性: ⭐⭐⭐⭐ 提高代码质量和可维护性


🎯 学习目标

  • 掌握类型注解的基本语法
  • 学会使用typing模块
  • 理解dataclasses的用法

📝 类型注解基础

基本类型注解

Python
# Python 3.9+ 推荐:直接使用内置类型的泛型语法
# 无需从 typing 导入 List, Dict 等(已不推荐)

# 变量注解
name: str = "张三"
age: int = 25
height: float = 1.75
is_student: bool = True

# 函数注解
def greet(name: str) -> str:
    return f"Hello, {name}!"

def calculate_sum(numbers: list[int]) -> int:
    return sum(numbers)

# 可选类型(Python 3.10+ 推荐用 X | None)
def find_user(user_id: int) -> str | None:
    if user_id == 1:
        return "张三"
    return None

# 多种类型(Python 3.10+ 使用 |)
def process(value: int | str) -> str:
    return str(value)

# Python 3.9 兼容写法(使用 typing 模块)
from typing import Optional, Union
def find_user_compat(user_id: int) -> Optional[str]:  # 等价于 str | None
    return None

常用类型

Python
from typing import Any
from collections.abc import Callable

# 列表(Python 3.9+)
numbers: list[int] = [1, 2, 3]
names: list[str] = ["张三", "李四"]

# 字典
config: dict[str, Any] = {"name": "test", "count": 10}
scores: dict[str, int] = {"张三": 85, "李四": 90}

# 元组
point: tuple[int, int] = (10, 20)
rgb: tuple[int, int, int] = (255, 128, 0)

# 集合
unique_numbers: set[int] = {1, 2, 3}

# 可调用类型
# Callable[[参数类型列表], 返回类型]:表示接受两个int参数、返回int的函数
def apply(func: Callable[[int, int], int], a: int, b: int) -> int:
    return func(a, b)

# Any类型(慎用)
def process_any(value: Any) -> None:
    pass

🎯 泛型和TypeVar

Python
from typing import TypeVar, Generic

T = TypeVar("T")  # 定义类型变量T,用于泛型编程,表示"任意类型"

def get_first(items: list[T]) -> T:
    return items[0]

# 泛型类
class Box(Generic[T]):  # 继承Generic[T]使类成为泛型类,T在实例化时由参数推断
    def __init__(self, content: T):
        self.content = content

    def get(self) -> T:
        return self.content

box_int = Box(42)      # Box[int]
box_str = Box("hello")  # Box[str]

📦 dataclasses - 数据类

基本用法

Python
from dataclasses import dataclass

@dataclass  # @dataclass自动生成__init__、__repr__等常用方法
class Student:
    name: str
    age: int
    grades: list[int]

    def average_grade(self) -> float:
        return sum(self.grades) / len(self.grades) if self.grades else 0

# 自动生成__init__, __repr__, __eq__等方法
student = Student("张三", 20, [85, 90, 78])
print(student)  # Student(name='张三', age=20, grades=[85, 90, 78])
print(student.average_grade())  # 84.333...

# 自动比较
student1 = Student("张三", 20, [85])
student2 = Student("张三", 20, [85])
print(student1 == student2)  # True

高级特性

Python
from dataclasses import dataclass, field

@dataclass
class DataProcessor:
    name: str
    cache: dict = field(default_factory=dict)  # 可变默认值
    items: list[int] = field(default_factory=list)
    count: int = 0
    readonly: int = field(init=False)  # 只读,不在__init__中

    def __post_init__(self):
        """初始化后处理"""
        self.readonly = 42

# 使用
processor = DataProcessor("processor1")
print(processor)  # DataProcessor(name='processor1', cache={}, items=[], count=0, readonly=42)

🎨 Enum - 枚举类型

Python
from enum import Enum, auto

class Status(Enum):
    PENDING = auto()
    RUNNING = auto()
    COMPLETED = auto()
    FAILED = auto()

# 使用
status = Status.RUNNING
print(status)  # Status.RUNNING
print(status.value)  # 2

# 比较
if status == Status.RUNNING:
    print("正在运行")

# 在函数中使用
def update_status(status: Status):
    if status == Status.COMPLETED:
        print("任务完成")
    elif status == Status.FAILED:
        print("任务失败")

update_status(Status.COMPLETED)

💡 实用场景

场景1: 配置类

Python
from dataclasses import dataclass

@dataclass
class ModelConfig:
    """模型配置"""
    model_name: str
    learning_rate: float = 0.001
    batch_size: int = 32
    epochs: int = 100
    device: str = "cpu"
    checkpoint_path: str | None = None

# 使用
config = ModelConfig(
    model_name="ResNet50",
    learning_rate=0.0001,
    device="cuda"
)

def train_model(config: ModelConfig):
    print(f"训练模型: {config.model_name}")
    print(f"学习率: {config.learning_rate}")

train_model(config)

场景2: 类型验证装饰器

Python
from typing import get_type_hints
from functools import wraps

def validate_types(func):
    """运行时类型验证"""
    @wraps(func)  # @wraps保留被装饰函数的元信息(名称、文档字符串等)
    def wrapper(*args, **kwargs):
        hints = get_type_hints(func)  # 在运行时获取函数的类型注解字典

        # 验证参数
        for param_name, param_type in hints.items():
            if param_name == "return":
                continue

            value = kwargs.get(param_name)
            if value is not None and not isinstance(value, param_type):
                raise TypeError(
                    f"{param_name} should be {param_type}, got {type(value)}"
                )

        return func(*args, **kwargs)
    return wrapper

@validate_types
def process_data(name: str, count: int) -> None:
    print(f"Processing {count} items for {name}")

process_data(name="test", count=10)  # OK
# process_data(name="test", count="10")  # TypeError

📝 练习

  1. 为你的项目添加完整的类型注解
  2. 创建一个配置dataclass
  3. 实现类型验证装饰器

🎯 自我检查

  • 能正确使用类型注解
  • 理解typing模块的常用类型
  • 能使用dataclasses简化代码
  • 知道何时使用枚举

📚 延伸阅读


🎉 恭喜完成阶段2!

你已经完成了标准库实用指南的学习!

接下来建议你: 1. 回顾总结 - 整理这个阶段的笔记 2. 实际应用 - 用标准库写一个工具脚本 3. 进入阶段3 - 数据科学核心库