函数注解与类型提示

python/function/annotations2026-09-16 17:09:45

Python 的函数注解可以为参数和返回值附加元数据。注解经常被用作类型提示,帮助编辑器、类型检查器、框架和其他工具理解代码中的数据类型。

Python 运行时通常不会主动强制执行类型提示。具体是否进行检查、转换或校验,取决于使用这些注解的工具或框架。相关类型及规则可参阅 Python 官方的 typing 文档。

参数与返回值注解

参数注解写在参数名之后,返回值注解写在 -> 之后:

def search(query: str, top_k: int = 4) -> list[str]:
    return [query] * top_k

这里:

  • query: str 表示 query 预期为字符串;
  • top_k: int 表示 top_k 预期为整数;
  • -> list[str] 表示函数预期返回字符串列表;
  • = 4 是参数默认值,不是类型注解的一部分。

变量也可以使用注解:

request_id: str
retry_count: int = 0

常见类型表达式

内置容器可以声明元素类型:

names: list[str]
scores: dict[str, float]
coordinates: tuple[float, float]

联合类型 X | Y 表示值可以属于多个类型之一:

identifier: int | str

X | None 表示值也可以是 None:

character_id: str | None = None

“允许为 None”和“调用时可以省略”不是同一件事。类型表达式决定允许的值,默认值决定参数是否可以不传:

def find(name: str | None):      # 必须传参,但可以传 None
    ...

def find(name: str | None = None):  # 可以省略
    ...

Annotated

typing.Annotated 可以在一个类型之外附加由特定工具解释的元数据:

from typing import Annotated

UserName = Annotated[str, "non-empty user name"]

其中 str 仍然是基础类型,后面的值是附加元数据。不认识这些元数据的类型检查器通常仍会把它当作 str;认识它的框架则可以赋予元数据特定含义。

例如,FastAPI 的依赖注入可以把 Annotated 与 Depends 组合:

from typing import Annotated
from fastapi import Depends

async def require_user() -> User:
    ...

async def profile(
    user: Annotated[User, Depends(require_user)],
):
    return user

这里的 User 描述参数类型,Depends(require_user) 则告诉 FastAPI 如何获得这个参数。

运行时边界

Python 官方说明,运行时本身不强制检查函数和变量的类型注解。下面的调用不一定会因为参数类型不匹配而被 Python 自动拒绝:

def double(value: int) -> int:
    return value * 2

double("a")

静态类型检查器可以在运行前发现部分问题;Pydantic、FastAPI 等工具也可以在运行时读取注解并执行自己的校验或转换。因此,类型提示描述的是类型意图,实际运行时行为仍取决于函数实现和使用注解的工具。

本页目录