Python 中 typing 模块的类型注解

FreeGuideOnline 最新 2026-07-07

python def greet(name: str) -> str: return f"Hello, {name}"


`typing` 模块则提供了描述复杂数据结构的各种工具。

---

## 入门:基本类型注解

### 内置类型直接使用
对于简单类型,直接使用内置类型名即可,无需从 `typing` 导入:

```python
age: int = 25
price: float = 99.9
name: str = "Alice"
is_active: bool = True

对于函数参数与返回值:

def add(a: int, b: int) -> int:
    return a + b

typing 模块常用复合类型

当数据结构变复杂,就需要引入 typing

注解写法 含义
List[int] 整数列表
Dict[str, float] 字符串键,浮点数值的字典
Tuple[int, str] 二元组,第一个 int 第二个 str
Set[bytes] 字节串集合
Optional[str] 可以是 strNone
Union[int, str] 整数或字符串
Any 任意类型,关闭类型检查
Callable[[int], str] 可调用对象,接收 int 返回 str

示例:

from typing import List, Dict, Tuple, Optional, Union, Any, Callable

def process_items(items: List[str]) -> None:
    for item in items:
        print(item)

def get_student_scores() -> Dict[str, float]:
    return {"math": 92.5, "history": 88.0}

def get_dimensions() -> Tuple[int, int]:
    return (1920, 1080)

def find_user(name: str) -> Optional[dict]:
    # 可能返回字典,也可能返回 None
    if name in database:
        return database[name]
    return None

def parse_value(val: Union[int, str]) -> float:
    return float(val)

def execute(callback: Callable[[int], str], arg: int) -> str:
    return callback(arg)

类型别名:给复杂类型起个名

一遍遍写 List[Dict[str, Union[int, str]]] 会让代码难以维护。用类型别名(Type Alias)提升可读性。

from typing import List, Dict, Union

# 定义别名
Row = Dict[str, Union[int, str]]
Table = List[Row]

def display_table(table: Table) -> None:
    for row in table:
        print(row)

从 Python 3.10 开始,还可以用 TypeAlias 显式标记(推荐):

from typing import TypeAlias

Row: TypeAlias = Dict[str, Union[int, str]]

结构更清晰的 TypedDict

当字典具有固定键和类型时,TypedDict 比普通 Dict 更严格、更友好。

from typing import TypedDict

class Movie(TypedDict):
    title: str
    year: int
    rating: float
    watched: bool

def record_movie(movie: Movie) -> None:
    print(f"{movie['title']} ({movie['year']}) - {movie['rating']}")

# 正确的调用会被检查
movie_entry: Movie = {
    "title": "Inception",
    "year": 2010,
    "rating": 8.8,
    "watched": True
}
record_movie(movie_entry)

通过 TypedDict,IDE 可以提示字典应有字段,而 mypy 可以检测键名拼写错误。


泛型:打造可复用的容器类型

TypeVar 定义类型变量,可以创建泛型类或函数,保持类型安全的同时支持多种实际类型。

from typing import TypeVar, List

T = TypeVar('T')

def first_element(items: List[T]) -> T:
    return items[0]

# 类型检查器能推断出:
# first_element([1,2,3]) 返回 int
# first_element(["a","b"]) 返回 str

自定义泛型类:

from typing import Generic, TypeVar

K = TypeVar('K')
V = TypeVar('V')

class Pair(Generic[K, V]):
    def __init__(self, key: K, value: V):
        self.key = key
        self.value = value

p = Pair[str, int]("age", 30)  # 类型为 Pair[str, int]

高级但实用的类型

Literal:字面量限定

限制变量或参数必须是某几个具体的值,非常适用于模式匹配或配置选项。

from typing import Literal

def set_mode(mode: Literal["auto", "manual", "eco"]) -> None:
    print(f"Mode set to {mode}")

set_mode("auto")  # 正确
set_mode("turbo") # mypy 会报错

Final:禁止覆盖的常量

from typing import Final

MAX_CONNECTIONS: Final = 100
# MAX_CONNECTIONS = 200  # mypy 会报错

也可以在类中声明 Final 方法、属性。

Protocol:结构化鸭子类型

定义接口但不需要显式继承,只要一个类具有指定的方法和属性,就被认为是该类型。

from typing import Protocol

class SupportsClose(Protocol):
    def close(self) -> None: ...

class FileReader:
    def close(self) -> None:
        print("File closed")

def shutdown(resource: SupportsClose) -> None:
    resource.close()

shutdown(FileReader())  # 通过类型检查

NoReturn:永不返回的函数

通常用于抛出异常或无限循环的函数。

from typing import NoReturn

def fatal_error(msg: str) -> NoReturn:
    raise RuntimeError(msg)

常用类型兼容性场景

场景 正确写法
可以接收 None 的参数 Optional[str]str | None (3.10+)
参数可以是多种类型 Union[int, str]int | str
不知道或不关心类型 Any
参数可以是多种类型但区分明确 @overload 装饰器
字典缺少键但值可为 None Dict[str, Optional[int]]
表示“空” 通常用 None,配合 Optional

版本迁移:Python 3.9 / 3.10 后的新写法

自 Python 3.9 起,内置 listdict 等已经支持泛型语法,不再必须从 typing 导入 ListDict

# Python 3.9+ 推荐
def get_names() -> list[str]:
    return ["Alice", "Bob"]

def count_words(text: str) -> dict[str, int]:
    words = text.split()
    return {w: len(w) for w in words}

Python 3.10 引入了联合类型的 | 语法,完全取代 UnionOptional

def process(data: int | str | None) -> list[int | str]:
    if data is None:
        return []
    return [data]

不过在需要兼容旧版本时,仍应从 typing 导入 List 等。


如何开始使用类型检查

  1. 安装 mypy
    pip install mypy
    
  2. 在项目根目录创建 mypy.inipyproject.toml 配置基本选项。
  3. 运行:
    mypy your_script.py