Python类型检查Mypy
Python 类型检查 Mypy 详解
==================================
Mypy 是 Python 的静态类型检查器,通过在运行前分析代码类型注解
捕获潜在的类型错误,让 Python 代码享受静态类型语言的安全性。
一、安装与基本使用
------------------
# 安装 Mypy
# pip install mypy
# 验证安装版本
mypy --version
# 检查单个文件
mypy app.py
# 检查整个包
mypy src/
# 严格模式检查(推荐新项目使用)
mypy --strict src/
二、Mypy 配置文件
------------------
# 在 pyproject.toml 中配置 Mypy
"""
[tool.mypy]
# Python 版本设定
python_version = "3.11"
# 严格模式等价于启用以下所有选项
strict = true
# 要求所有函数都有类型注解
disallow_untyped_defs = true
# 禁止未类型化的装饰器
disallow_untyped_decorators = true
# 对 None 值的检查更严格
strict_equality = true
# 检查未使用的忽略注释
warn_unused_ignores = true
# 检查返回值类型与注解不匹配
warn_return_any = true
# 禁止隐式 Optional(如 x = None 不标注 Optional)
no_implicit_optional = true
# 允许重载装饰器
allow_redefinition = false
# 需要导入的模块也要类型检查
follow_imports = "normal"
# 排除不需要检查的文件
exclude = [
"build/",
"tests/",
"migrations/",
]
"""
# 也可以使用 mypy.ini 配置文件
"""
[mypy]
strict = True
disallow_untyped_defs = True
"""
三、@overload 装饰器
---------------------
# @overload 用于为同一个函数声明多个类型签名
from typing import overload, Union
# overload 声明输入 int 返回 int
@overload
def double(value: int) -> int: ...
# overload 声明输入 str 返回 str
@overload
def double(value: str) -> str: ...
# 实际的实现函数(不带类型装饰器)
def double(value):
# 根据输入类型返回不同类型
if isinstance(value, int):
return value * 2
elif isinstance(value, str):
return value + value
raise TypeError("不支持的类型")
# mypy 会检查调用是否匹配重载签名
result_int = double(5) # mypy 推断类型为 int
result_str = double("abc") # mypy 推断类型为 str
四、类型存根文件(Type Stubs)
-------------------------------
# 类型存根是 .pyi 文件,为无类型注解的库提供类型信息
# 安装第三方库的类型存根
# pip install types-requests
# pip install types-PyYAML
# pip install types-setuptools
# 自动生成存根文件
# mypy --generate-stubs mymodule
# 使用 stub 包检测缺失的存根
mypy --install-types
# 手动编写存根文件:example.pyi
"""
# example.pyi 文件内容
def process_data(name: str, count: int = 0) -> list[str]: ...
class DataHandler:
def __init__(self, source: str) -> None: ...
def fetch(self, query: str) -> dict[str, any]: ...
"""
五、reveal_type 调试
---------------------
# reveal_type 是 mypy 的特殊函数,用于调试类型推断
from typing import reveal_type
x = "hello world"
# 在 mypy 运行时会输出:Revealed type is "str"
reveal_type(x)
y = [1, 2, 3]
# 在 mypy 运行时会输出:Revealed type is "list[int]"
reveal_type(y)
z = {"name": "张三", "age": 30}
# 在 mypy 运行时会输出:Revealed type is "dict[str, str | int]"
reveal_type(z)
# reveal_type 仅在 mypy 检查时生效,运行时无任何效果
# 相当于注释,不产生运行时开销
六、类型忽略注释
-----------------
# 当 mypy 误报或需要绕过类型检查时使用忽略注释
from typing import Any
# 忽略特定行的类型错误
value: Any = some_external_function() # type: ignore
# 指定忽略的错误码
x = unsafe_function() # type: ignore[assignment]
# 对整个文件级别的忽略
"""
# mypy: ignore-errors
"""
# 在 pyproject.toml 中忽略特定模块的错误
"""
[[tool.mypy.overrides]]
module = "legacy_module.*"
ignore_errors = true
"""
七、高级类型特性
----------------
from typing import TypedDict, Literal, Protocol
# TypedDict —— 字典的结构化类型
class UserDict(TypedDict):
# 定义字典的键值类型
name: str
age: int
email: str
user: UserDict = {"name": "李四", "age": 28, "email": "li@example.com"}
# Literal —— 限定字面量值
def set_mode(mode: Literal["dev", "prod", "test"]) -> None:
# mode 只能是 "dev" "prod" "test" 之一
print(f"模式设置为: {mode}")
# Protocol —— 结构子类型(鸭子类型)
class Drawable(Protocol):
# 定义协议:任何有 draw 方法的类型
def draw(self) -> None: ...
def render(obj: Drawable) -> None:
# 不需要继承,只需有 draw 方法
obj.draw()
八、与项目集成
--------------
# 在 pre-commit 中配置 mypy
"""
repos:
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.7.0
hooks:
- id: mypy
args: [--strict, --ignore-missing-imports]
additional_dependencies: [types-requests]
"""
# 在 CI 中运行 mypy
mypy src/ --strict --warn-unused-configs
# 检查并生成报告
mypy src/ --html-report mypy_report
# 生成 HTML 格式的类型覆盖报告
# Mypy 将 Python 的动态灵活性与静态类型的严谨性结合,
# 在大型项目中显著降低运行时类型错误的发生率。
更多推荐


所有评论(0)