Python不强制类型检查,需区分静态检查(mypy)和运行时检查(isinstance、typeguard、pydantic);二者目标不同、工具不同、不可替代。

Python 本身不强制执行函数参数的类型检查,类型注解(如 x: int)只是提示,运行时完全忽略。要真正校验参数类型,需明确区分两种场景:静态检查(开发阶段) 和 运行时检查(执行阶段),二者目标不同、工具不同、不可互相替代。
静态类型检查:用 mypy 在运行前发现问题
这是最常用、开销最小的方式,适合团队协作和长期维护。
- 给函数加上完整类型注解,例如:
def calc_total(price: float, quantity: int) -> float: - 安装并运行
mypy:pip install mypy,然后执行mypy your_file.py - 若调用写成
calc_total("19.99", 5),mypy 会立刻报错:Argument 1 to "calc_total" has incompatible type "str"; expected "float" - 推荐加严格选项:
mypy --disallow-untyped-defs --check-untyped-args,避免漏注解或混用未注解参数
运行时类型检查:函数执行中实时拦截错误
适用于 API 入口、关键业务逻辑或需要向用户明确反馈的场景。
- 用
isinstance()手动判断(轻量、无依赖):
在函数开头检查:if not isinstance(price, (int, float)):→ 抛TypeError - 用
@typechecked装饰器(来自typeguard库):pip install typeguard,然后装饰函数,它会自动按注解校验所有参数和返回值 - 对复杂结构(如嵌套字典、列表),
pydantic更合适:
定义BaseModel子类描述参数结构,调用前用.model_validate()解析并校验
注意 Union、Optional 等复合类型的写法
别写错语法,否则 mypy 或运行时库无法识别。
- 接受多个类型:用
Union[int, str](Python int | str(3.10+) - 允许为 None:用
Optional[str](等价于Union[str, None]),不要写str or None(语法错误) - 限定固定取值:用
Literal["start", "stop"],mypy 会拒绝传入"pause" - 所有这些写法只影响类型检查工具,不改变运行时行为——
Optional[str]不会自动把None变成空字符串
别混淆“声明”和“执行”
这是最常见的误区:写了 def f(x: List[int]) -> bool:,就以为传入 f([1, "a"]) 会报错。实际上:
- Python 解释器照常执行,不会拦;
- mypy 只能在你主动运行时发现(且只查静态用法,不深入列表内容);
- typeguard 会检查
x是不是list,但默认不递归校验元素类型(需额外配置); - 真要验证列表里全是 int,得自己写循环 +
isinstance(item, int),或用 pydantic 的list[int](v2+ 支持)

















