typing 模块提供了许多高级特性,这些特性可以帮助开发者编写更健壮、更易维护的代码。 以下是一些高级用法的详细解析,结合了最新的 typing 模块功能和 typing-extensions 包的内容。
基础类型
Any:任意类型
表示变量可以是任何类型,完全禁用类型检查(慎用,优先用更具体的类型)。
from typing import Any
def print_anything(data: Any) -> None:
print(data) # 可以是 int、str、dict 等任意类型
print_anything(42) # 合法
print_anything("hello")# 合法
Union:联合类型
表示变量可以是多个类型中的一种(Python 3.10+ 可用 | 替代)。
from typing import Union
def parse_input(data: Union[str, int]) -> str:
return str(data) # 接受 str 或 int,返回 str
# Python 3.10+ 等价写法
def parse_input_v2(data: str | int) -> str:
return str(data)
print(parse_input(100)) # 输出 "100"
print(parse_input("abc")) # 输出 "abc"
Optional:可选类型
等价于 Union[T, None],表示变量可能是某个类型或 None。
from typing import Optional
def find_user(user_id: int) -> Optional[str]:
if user_id == 1:
return "Alice" # 返回 str
else:
return None # 返回 None
user = find_user(1)
if user is not None:
print(user.upper()) # 类型检查器知道此处 user 是 str
容器类型
List/list:列表
指定列表元素的类型。
from typing import List
def sum_numbers(nums: List[int]) -> int:
return sum(nums) # 确保列表元素全是 int
# Python 3.9+ 内置泛型写法
def sum_numbers_v2(nums: list[int]) -> int:
return sum(nums)
sum_numbers([1, 2, 3]) # 合法
sum_numbers(["a", "b"]) # 类型检查报错(元素不是 int)
Dict / dict:字典
指定键和值的类型。
from typing import Dict
def get_population() -> Dict[str, int]:
return {"China": 1410, "India": 1380} # 键为 str,值为 int
# Python 3.9+ 写法
def get_population_v2() -> dict[str, int]:
return {"China": 1410, "India": 1380}
population = get_population()
print(population["China"] + 10) # 类型检查器知道值是 int
Tuple / tuple:元组
- 固定长度和类型:精确指定每个位置的类型。
- 不定长元组:用 ... 表示剩余元素类型相同。
from typing import Tuple
def get_coordinates() -> Tuple[float, float]:
return (40.7128, -74.0060) # 两个 float 元素
# 不定长元组(Python 3.9+)
def process_data(data: tuple[int, ...]) -> int:
return sum(data) # 所有元素必须是 int
process_data((1, 2, 3)) # 合法
process_data((1, "a")) # 类型检查报错(第二个元素不是 int)
Set / set:集合
指定集合元素的类型。
from typing import Set
def unique_values(items: Set[str]) -> int:
return len(items) # 元素必须是 str
# Python 3.9+ 写法
def unique_values_v2(items: set[str]) -> int:
return len(items)
unique_values({"apple", "banana"}) # 合法
unique_values({1, 2}) # 类型检查报错
泛型与类型变量
TypeVar:定义泛型类型变量
用于定义“类型变量”,让函数、类、类型别名在静态检查阶段具备参数化的能力(类似 C++/Java 的模板或泛型)。
from typing import TypeVar, Generic, List
T = TypeVar('T') # 可以是任何类型
def first_element(items: List[T]) -> T:
return items # 返回类型与列表元素类型相同
print(first_element([1, 2, 3])) # 返回 int 类型(1)
print(first_element(["a", "b"])) # 返回 str 类型("a")
T = TypeVar('T') # 可以是任何类型
S = TypeVar('S', bound=str) # 必须是 str 的子类型
U = TypeVar('U', int, float) # 只能是 int 或 float(约束)
T_co = TypeVar('T_co', covariant=True) # 协变:允许子类型替换
T_contra = TypeVar('T_contra', contravariant=True) # 逆变:允许父类型替换
Sequence
只读可变长度序列”的泛型协议,用于描述“像列表一样的东西”,但不需要是 list 本身。
类型 | 可否修改 | 是否可变长度 | 示例 |
---|---|---|---|
Sequence[T] | ❌ 只读 | ✅ | tuple[int, ...] 、List[int] |
MutableSequence[T] | ✅ 读写 | ✅ | List[int] 、deque[int] |
Iterable[T] | 只读迭代器 | ❓ | range(10) 、generator |
Container[T] | 只读 in 检查 | ❓ | set[int] |
作为函数参数
from typing import Sequence
def total(nums: Sequence[int]) -> int:
return sum(nums)
total([1, 2, 3]) # ✅ list
total((1, 2, 3)) # ✅ tuple
total(range(5)) # ✅ range
total("123") # ✅ str 也是 Sequence[str]
作为返回值
from typing import Sequence
def squares(n: int) -> Sequence[int]:
return [i * i for i in range(n)] # 返回 list,但符合 Sequence[int]
协变(covariant)
from typing import Sequence, TypeVar
T_co = TypeVar('T_co', covariant=True)
def animals(x: Sequence[T_co]) -> T_co:
return x[0]
cats: Sequence[Cat] = [Cat()]
animals(cats) # ✅ 协变允许
联合类型
from typing import Sequence, Union
NumberSeq = Sequence[Union[int, float]]
def avg(nums: NumberSeq) -> float:
return sum(nums) / len(nums)
TypeVarTuple
Python 3.11 起引入的 TypeVarTuple(PEP 646)提供了 可变长泛型(variadic generics) 能力,
允许一个泛型类型或函数接受 “任意数量”的类型参数,从而精确描述诸如“任意维度的张量”、“任意长度的元组”等场景。
基本语法
from typing import TypeVarTuple
Ts = TypeVarTuple('Ts') # 一个类型变量元组
# ✅ 正确:始终用 * 展开
def foo(*args: *Ts) -> tuple[*Ts]: ...
# ❌ 错误:忘记 *
def bar(x: tuple[Ts]) -> ... # Type checker 报错
函数:任意长度元组变换
from typing import TypeVar, TypeVarTuple
T = TypeVar('T')
Ts = TypeVarTuple('Ts')
def move_first(t: tuple[T, *Ts]) -> tuple[*Ts, T]:
return (*t[1:], t[0])
reveal_type(move_first((1, 'a', True))) # tuple[str, bool, int]
泛型类:任意维度数组
from typing import Generic, TypeVar, TypeVarTuple
DType = TypeVar('DType')
Shape = TypeVarTuple('Shape')
class Array(Generic[DType, *Shape]):
def __abs__(self) -> Array[DType, *Shape]: ...
def broadcast_to(self, new_shape: tuple[*Shape]) -> Array[DType, *Shape]: ...
# 使用
Height = int
Width = int
img: Array[float, Height, Width, 3] = Array()
默认值
from typing import Unpack, TypeVarTuple
DefaultShape = TypeVarTuple('DefaultShape', default=Unpack[tuple[int, int]])
class Tensor[*DefaultShape]:
...
Generic:泛型类
创建可参数化的类。
from typing import Generic, TypeVar, List
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()
# 实例化时指定具体类型
stack_int = Stack:ml-search[int]
stack_int.push(42)
stack_int.push("hello") # 类型检查报错(非 int 类型)
stack_str = Stack:ml-search[str]
stack_str.push("world") # 合法
函数与回调
Callable:函数签名
定义回调函数的参数和返回值类型。
Callable[..., Any]
方括号里是 参数列表 和 返回值 的“类型提示”。
...
(三个点,Ellipsis)是“参数形状不关心”的简写:- 不限制参数个数、不限制参数类型。
- 等价于写 typing.ParamSpec 里的 *args, **kwargs 的“通配”效果。
- 最后一个 Any 表示“返回值类型也不限制”。
from typing import Callable
def apply_operation(
x: int,
y: int,
op: Callable[[int, int], int] # 接受两个 int 参数,返回 int
) -> int:
return op(x, y)
# 合法操作
print(apply_operation(3, 4, lambda a, b: a * b)) # 输出 12
# 非法操作(类型检查报错)
apply_operation(3, 4, lambda a: a) # 回调函数参数数量不匹配
迭代器和生成器
- Generator[YieldType, SendType, ReturnType]:定义生成器的产出值、发送值和返回值。
- Iterable[T]:可迭代对象。
- Iterator[T]:迭代器。
from typing import Generator, Iterable, Iterator
def count_up_to(n: int) -> Generator[int, None, None]:
"""生成器产出 int,不接收 send 值,无返回值"""
i = 1
while i <= n:
yield i
i += 1
def print_all(items: Iterable[str]) -> None:
for item in items:
print(item)
def square_numbers(nums: list[int]) -> Iterator[int]:
return (num ** 2 for num in nums) # 返回生成器表达式(迭代器)
# 使用示例
for num in count_up_to(5):
print(num) # 输出 1, 2, 3, 4, 5
高级类型
Literal
字面量类型(Python 3.8+),限制变量只能取特定的字面量值。
from typing import Literal
def set_status(status: Literal["active", "inactive"]) -> None:
print(f"Status set to {status}")
set_status("active") # 合法
set_status("pending") # 类型检查报错(不在允许的字面量中)
TypedDict
类型化字典(Python 3.8+),定义字典的键和值类型,增强代码可读性和安全性。
from typing import TypedDict
class User(TypedDict):
name: str
age: int
is_active: bool
def create_user() -> User:
return {
"name": "Bob",
"age": 30,
"is_active": True,
"email": "bob@example.com" # 类型检查报错(不在定义中)
}
Protocol
结构子类型(Python 3.8+),定义接口协议(无需继承,只要实现特定方法)。
from typing import Protocol
class Printable(Protocol):
def print(self) -> None:
... # 只需实现 print 方法即可符合协议
class Document:
def print(self) -> None:
print("Printing document...")
class Image:
def print(self) -> None:
print("Printing image...")
def log_print(obj: Printable) -> None:
obj.print()
log_print(Document()) # 合法
log_print(Image()) # 合法
其他实用类型
NewType:创建新类型
定义具有语义的新类型(运行时无开销,仅用于类型检查)。
from typing import NewType
UserId = NewType("UserId", int) # UserId 是 int 的派生类型
def get_user(id: UserId) -> str:
return f"User {id}"
user_id = UserId(1001) # 创建 UserId 类型变量
print(get_user(user_id)) # 合法
# 直接传递 int 会报错
print(get_user(1001)) # 类型检查报错(需要 UserId 类型)
Type:类类型
表示类本身(而非实例),常用于工厂模式。
- Type[Dog] 只接受 Dog 及其子类
- Type[object] 接受 任何类
from typing import Type
class Animal:
def speak(self) -> str:
return "..."
class Dog(Animal):
def speak(self) -> str:
return "Woof!"
def create_animal(cls: Type[Animal]) -> Animal:
return cls() # 创建类的实例
print(create_animal(Dog).speak()) # 输出 "Woof!"
Final
常量(Python 3.8+),标记变量不可被重新赋值。
from typing import Final
MAX_SIZE: Final[int] = 100
MAX_SIZE = 200 # 类型检查报错(不可修改)
Annotated
Annotated 允许你在类型提示中添加元数据,这可以用于验证或文档目的。
给类型附加任意元数据的机制,而不改变运行时的实际类型。
注意:大量使用可能影响启动时间(但运行时无影响)
from typing import Annotated
def process_value(value: Annotated[int, "Must be a positive integer"]) -> int:
if value < 0:
raise ValueError("Value must be positive!")
return value
print(process_value(10)) # 正确
# print(process_value(-1)) # 会抛出 ValueError
基本用法
from typing import Annotated
# 基本语法
# Annotated[<type>, <metadata1>, <metadata2>, ...]
# 1) 定义
UserId = Annotated[int, "用户ID", range(1, 9999)]
# 2) 使用
def get_user(uid: UserId) -> dict:
...
- 运行时:uid 仍然是普通的 int,没有任何额外行为。
- 静态工具 / 运行时库:可以读取 "用户ID" 或 range(...) 做验证、文档或 IDE 提示。
工作原理
Annotated[T, *metadata]
返回一个特殊的“代理类型”,元数据存放在 metadata 属性里:
>>> from typing import get_type_hints, get_origin, get_args
>>> get_type_hints(get_user) # 返回裸 int,不影响
{'uid': <class 'int'>}
>>> get_origin(UserId), get_args(UserId)
(<class 'int'>, ('用户ID', range(1, 9999)))
常见场景实战
场景 | 示例 | 使用者 |
---|---|---|
数值约束 | Annotated[int, Field(ge=0, le=120)] | Pydantic |
字符串格式 | Annotated[str, StringConstraints(min_length=3)] | Pydantic |
依赖注入 | Annotated[Database, Depends(get_db)] | FastAPI |
命令行选项 | Annotated[int, typer.Argument(help="端口")] | Typer |
数据库 | Annotated[str, Column(String(50))] | SQLAlchemy 2.0 |
FastAPI 参数扩展
from fastapi import FastAPI, Query
from typing import Annotated
app = FastAPI()
@app.get("/items/")
async def read_items(
q: Annotated[str, Query(min_length=3, max_length=50)]
):
return {"q": q}
添加验证约束
from pydantic import BaseModel, Field
from typing import Annotated
class User(BaseModel):
age: Annotated[int, Field(gt=0, lt=120)]
email: Annotated[str, Field(pattern=r".+@.+\..+")]
业务语义标注
from typing import Annotated
# 标记敏感数据
Password = Annotated[str, "sensitive_data"]
# 标记测量单位
Temperature = Annotated[float, "unit:celsius"]
运行时访问元数据
from typing import Annotated, get_type_hints
def func(param: Annotated[int, "range:1-100"]):
pass
hints = get_type_hints(func, include_extras=True)
print(hints["param"].__metadata__) # 输出: ("range:1-100",)
嵌套与组合
PositiveInt = Annotated[int, Range(1, 999)]
UserId = Annotated[PositiveInt, "Primary key"]
def create(uid: UserId) -> None: ...
Self
Self 类型简化了返回当前实例的方法的类型注解。
from typing import Self
class Builder:
def __init__(self):
self.data = []
def add(self, value: int) -> Self:
self.data.append(value)
return self
builder = Builder().add(10).add(20)
print(builder.data) # 输出: [10, 20]
Unpack 和变长泛型
Unpack 用于变长泛型,允许你解包类型序列。
from typing import TypeVarTuple, Unpack
Shape = TypeVarTuple("Shape")
def print_shapes(*shapes: Unpack[Shape]) -> None:
for shape in shapes:
print(shape)
print_shapes(1, 2, 3) # 正确
协变与逆变
协变(Covariant)
允许子类替代父类(常见于只读容器)。
from typing import TypeVar, Generic
class Animal: pass
class Dog(Animal): pass
T_co = TypeVar("T_co", covariant=True)
class ImmutableList(Generic[T_co]):
def __init__(self, items: list[T_co]) -> None:
self.items = items
def get(self, index: int) -> T_co:
return self.items[index]
# 协变允许将 ImmutableList[Dog] 赋值给 ImmutableList[Animal]
animals: ImmutableList[Animal] = ImmutableList([Dog(), Dog()])
逆变(Contravariant)
允许父类替代子类(常见于函数参数)。
from typing import TypeVar, Generic, Callable
class Animal: pass
class Dog(Animal): pass
T_contra = TypeVar("T_contra", contravariant=True)
class EventHandler(Generic[T_contra]):
def handle(self, data: T_contra) -> None:
print(f"Handling {type(data).__name__}")
# 逆变允许将 EventHandler[Animal] 赋值给 EventHandler[Dog]
def process_event(handler: EventHandler[Dog]) -> None:
handler.handle(Dog())
animal_handler = EventHandler:ml-search[Animal]
process_event(animal_handler) # 合法
On this page
- 基础类型
- Any:任意类型
- Union:联合类型
- Optional:可选类型
- 容器类型
- List/list:列表
- Dict / dict:字典
- Tuple / tuple:元组
- Set / set:集合
- 泛型与类型变量
- TypeVar:定义泛型类型变量
- Sequence
- TypeVarTuple
- Generic:泛型类
- 函数与回调
- Callable:函数签名
- 迭代器和生成器
- 高级类型
- Literal
- TypedDict
- Protocol
- 其他实用类型
- NewType:创建新类型
- Type:类类型
- Final
- Annotated
- Self
- Unpack 和变长泛型
- 协变与逆变
- 协变(Covariant)
- 逆变(Contravariant)