使用typing增强Python代码的可读性、可维护性,并帮助静态分析工具进行错误检查。
Python 的 typing 模块是用于 类型注解和静态类型检查 的标准库工具。它为你编写类型安全、可读性强的大型代码提供了支持。
基础类型和泛型容器类型
基础类型注解
1
| int, float, str, bool, bytes
|
泛型容器类型
类型 |
用法示例 |
List |
List[int] — 整数列表 |
Dict |
Dict[str, float] — 键为字符串,值为浮点数 |
Tuple |
Tuple[int, str] — 二元组 |
Set |
Set[int] |
FrozenSet |
FrozenSet[str] |
- Python 3.9+ 支持原生写法,如
list[int]
替代 List[int]
。
例如:
1 2 3 4 5 6
| from typing import List
def average(scores: List[float]) -> float: return sum(scores) / len(scores)
print(average([90.0, 85.5, 78.0]))
|
1 2 3 4 5 6 7
| from typing import Dict
def get_student_score(name: str, records: Dict[str, float]) -> float: return records[name]
data = {"Alice": 91.5, "Bob": 88.0} print(get_student_score("Alice", data))
|
1 2 3 4 5 6 7
| from typing import Tuple
def get_student_info() -> Tuple[str, int]: return ("Alice", 20)
name, age = get_student_info() print(name, age)
|
1 2 3 4 5 6 7 8 9 10
| from typing import Dict, List
def total_scores(data: Dict[str, List[int]]) -> Dict[str, int]: return {name: sum(scores) for name, scores in data.items()}
records = { "Alice": [90, 85, 92], "Bob": [78, 80, 74] } print(total_scores(records))
|
通用类型工具
工具 |
描述 |
Any |
任意类型 |
Union |
多种类型之一,例如 Union[int, str] |
Optional |
可以是某种类型或 None,等价于 Union[T, None] |
Callable |
函数类型,例如 Callable[[int, int], str] 表示接受两个 int 返回 str 的函数 |
Literal |
指定字面值,例如 Literal[‘yes’, ‘no’] |
TypeVar |
泛型类型变量(定义泛型函数或类时使用) |
Generic |
创建自定义泛型类时用 |
Final |
声明不能被重写或赋值的变量/属性 |
ClassVar |
用于声明类变量,而非实例变量 |
例如: |
|
TypeVar
1 2 3 4 5 6 7 8 9
| from typing import TypeVar, Tuple
T = TypeVar('T')
def swap(a: T, b: T) -> Tuple[T, T]: return b, a
print(swap(1, 2)) print(swap("hi", "bye"))
|
- T 可以是任何类型(int、str、float…)
Generic
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| from typing import TypeVar, Generic
T = TypeVar('T')
class Box(Generic[T]): def __init__(self, content: T): self.content = content
def get(self) -> T: return self.content
int_box = Box print(int_box.get())
str_box = Box[str]("hello") print(str_box.get())
|
Box[T]
表示这是一个“存放任意类型 T 的盒子”
Generic[T]
表示类是“泛型类”
Any
1 2 3 4 5 6 7 8
| from typing import Any
def print_anything(x: Any) -> None: print(f"Received: {x}")
print_anything(42) print_anything("hello") print_anything([1, 2, 3])
|
结构化和协议
类型 |
描述 |
Protocol |
定义接口或行为协议(Python 3.8+) |
TypedDict |
类似 dict 的结构化类型注解 |
NamedTuple |
类型注解版本的命名元组 |
dataclass |
与 @dataclass 一起使用可以加注解 |
例如: |
|
TypedDict
1 2 3 4 5 6 7 8 9 10 11 12
| from typing import TypedDict
class User(TypedDict): id: int name: str is_active: bool
def greet(user: User) -> str: return f"Hello, {user['name']}!"
u = {"id": 1, "name": "Alice", "is_active": True} print(greet(u))
|
- 明确了 user 必须包含哪些字段
- 静态检查工具(如 mypy)可以发现拼写错误或字段缺失
Protocol
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| from typing import Protocol
class Reader(Protocol): def read(self) -> str: ...
class FileReader: def read(self) -> str: return "data from file"
class Dummy: def read(self) -> str: return "test data"
def load(r: Reader) -> str: return r.read()
print(load(FileReader())) print(load(Dummy()))
|
当你只关心某个对象是否有某些方法或属性(而不是它的具体类型),使用 Protocol 可以定义“接口”,实现 Python 的“结构子类型检查”。
- load() 不关心对象的真实类型,只要有 .read() 方法就行
- 非侵入式,“只要像鸭子,它就能飞”(典型的 duck typing)
dataclasses
1 2 3 4 5 6 7 8 9 10 11
| from dataclasses import dataclass
@dataclass class User: id: int name: str is_active: bool = True
u = User(id=1, name="Alice") print(u)
|
- 自动生成了 init() 方法
- 自动实现了 repr() 和 eq() 等方法
1 2 3 4 5 6 7 8 9 10 11
| from dataclasses import dataclass
@dataclass(order=True) class Product: price: float name: str
p1 = Product(19.9, "A") p2 = Product(29.9, "B")
print(p1 < p2)
|
1 2 3 4 5 6 7 8 9
| from dataclasses import dataclass, field
@dataclass class Token: value: str secret: str = field(repr=False, compare=False)
t1 = Token("abc", "secret123") print(t1)
|
忽略某个字段:field(repr=False, compare=False, default=…)
特殊类型工具
类型 |
描述 |
NewType |
定义新的类型别名,例如:UserId = NewType(‘UserId’, int) |
Type |
类对象的类型,例如 Type[BaseClass] |
Self |
指代自身(Python 3.11+) |
例如: |
|
NewType
创建“伪新类型”,用于静态类型区分
1 2 3 4 5 6 7 8 9
| from typing import NewType
UserId = NewType('UserId', int)
def get_user_name(user_id: UserId) -> str: return f"User#{user_id}"
get_user_name(UserId(123))
|
Type
Type[T]
接收一个类对象(而不是实例)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| from typing import Type
class Animal: def speak(self) -> str: return "..."
class Dog(Animal): def speak(self) -> str: return "Woof!"
def make_animal(animal_cls: Type[Animal]) -> Animal: return animal_cls()
a = make_animal(Dog) print(a.speak())
|
Type[Animal]
表示“Animal 的子类”,不是实例。
Self(Python 3.11+)
用于方法返回当前类类型
1 2 3 4 5 6 7 8 9 10 11 12
| from typing import Self
class Builder: def set_name(self, name: str) -> Self: self.name = name return self
def set_age(self, age: int) -> Self: self.age = age return self
b = Builder().set_name("Alice").set_age(30)
|
- Self 解决了链式调用返回类型难以表达的问题。
- 自动适配子类返回自身,无需硬编码类名。