第8章:类型提示
一、导读
1.1 本章学习目标
第8章讲解 Python 的类型提示系统:类型注解、Protocol、泛型、类型检查。
本章核心学习目标:
- 掌握类型注解:变量、函数、类的类型标注
- 理解 Protocol:结构化子类型
- 掌握泛型:Generic 和 TypeVar
- 了解 mypy 类型检查
1.2 为什么本章如此重要
类型提示让 Python 代码更安全、更易维护。大型项目尤其需要类型检查来捕获错误。
1.3 核心问题引导
类型提示影响运行时性能吗?
Protocol 和 ABC 有什么区别?
泛型如何在 Python 中使用?
二、核心概念详解
2.1 类型注解
python
from typing import Optional, Union
def greet(name: str, greeting: str = "Hello") -> str:
return f"{greeting}, {name}!"
def process(data: list[int]) -> dict[str, int]:
return {"sum": sum(data), "count": len(data)}
# Optional = Union[X, None]
def find_user(user_id: int) -> Optional[dict]:
# 可能返回 dict 或 None
pass
# 复杂类型
from typing import Callable, Iterator
def apply(func: Callable[[int, int], int], a: int, b: int) -> int:
return func(a, b)
def count_to(n: int) -> Iterator[int]:
for i in range(n):
yield i2.2 Protocol
python
from typing import Protocol
class Drawable(Protocol):
def draw(self) -> None:
...
class Circle:
def __init__(self, radius: float):
self.radius = radius
def draw(self) -> None:
print(f"Drawing circle with radius {self.radius}")
class Square:
def __init__(self, side: float):
self.side = side
def draw(self) -> None:
print(f"Drawing square with side {self.side}")
# 不需要继承 Drawable,只要有 draw 方法就行
def render(shape: Drawable) -> None:
shape.draw()
render(Circle(5)) # OK
render(Square(3)) # OK (结构化子类型)2.3 泛型
python
from typing import Generic, TypeVar
T = TypeVar('T')
class Stack(Generic[T]):
def __init__(self):
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) -> T:
return self._items[-1]
def is_empty(self) -> bool:
return len(self._items) == 0
int_stack: Stack[int] = Stack()
int_stack.push(42)
# int_stack.push("hello") # mypy 报错
str_stack: Stack[str] = Stack()
str_stack.push("hello")三、实战案例
3.1 案例一:类型安全的 Repository
python
from typing import Protocol, TypeVar, Generic
from dataclasses import dataclass
T = TypeVar('T')
ID = TypeVar('ID')
@dataclass
class User:
id: int
name: str
email: str
class Repository(Protocol[T, ID]):
def get(self, id: ID) -> T | None: ...
def save(self, entity: T) -> T: ...
def delete(self, id: ID) -> bool: ...
def find_all(self) -> list[T]: ...
class UserRepository:
def __init__(self):
self._users: dict[int, User] = {}
def get(self, id: int) -> User | None:
return self._users.get(id)
def save(self, user: User) -> User:
self._users[user.id] = user
return user
def delete(self, id: int) -> bool:
return self._users.pop(id, None) is not None
def find_all(self) -> list[User]:
return list(self._users.values())四、本章小结
类型提示提高代码可读性和安全性
Protocol 提供结构化子类型,无需继承
泛型让类和函数支持多种类型
五、思考与练习
类型提示在运行时会被检查吗?
如何用 TypeVar 约束类型?