python-mypy
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePython mypy — Static Type Checking
Python mypy — 静态类型检查
Mypy is an optional static type checker for Python that catches type errors at development time without runtime overhead. It combines the expressive power of Python with a powerful type system based on PEP 484, enabling gradual migration from dynamic to static typing.
Mypy是一款可选的Python静态类型检查工具,可在开发阶段捕获类型错误,且不会带来运行时开销。它结合了Python的表达能力与基于PEP 484的强大类型系统,支持从动态类型到静态类型的逐步迁移。
Installation
安装
bash
pip install mypybash
pip install mypyInstall type stubs for common third-party libraries
为常见第三方库安装类型存根
pip install types-requests types-PyYAML types-boto3
pip install types-requests types-PyYAML types-boto3
Run mypy
运行mypy
mypy src/
mypy --strict src/
undefinedmypy src/
mypy --strict src/
undefinedCore Annotation Patterns
核心注解模式
Functions
函数
Annotate all function signatures — return type and all parameters:
python
from collections.abc import Iterable, Sequence
def process(items: list[str], limit: int = 10) -> list[str]:
return items[:limit]为所有函数签名添加注解——包括返回类型和所有参数:
python
from collections.abc import Iterable, Sequence
def process(items: list[str], limit: int = 10) -> list[str]:
return items[:limit]Use abstract types for parameters (accept more, restrict less)
为参数使用抽象类型(接受更多类型,限制更少)
def summarize(records: Iterable[dict[str, str]]) -> str:
return ", ".join(r["name"] for r in records)
def summarize(records: Iterable[dict[str, str]]) -> str:
return ", ".join(r["name"] for r in records)
None return type for procedures
无返回值的过程式函数
def log_event(event: str, level: str = "INFO") -> None:
print(f"[{level}] {event}")
undefineddef log_event(event: str, level: str = "INFO") -> None:
print(f"[{level}] {event}")
undefinedOptional and Union
可选类型与联合类型
python
undefinedpython
undefinedPython 3.10+ syntax (preferred)
Python 3.10+语法(推荐)
def find_user(user_id: int) -> str | None:
...
def find_user(user_id: int) -> str | None:
...
Python 3.9 and earlier
Python 3.9及更早版本
from typing import Optional, Union
def find_user(user_id: int) -> Optional[str]:
...
from typing import Optional, Union
def find_user(user_id: int) -> Optional[str]:
...
Union for multiple possible types
多可能类型的联合
def normalize_id(user_id: int | str) -> str:
if isinstance(user_id, int):
return f"user-{user_id}"
return user_id
undefineddef normalize_id(user_id: int | str) -> str:
if isinstance(user_id, int):
return f"user-{user_id}"
return user_id
undefinedClasses
类
python
from typing import ClassVar
class Repository:
default_limit: ClassVar[int] = 100
def __init__(self, name: str, url: str) -> None:
self.name = name
self.url = url
self._cache: dict[str, list[str]] = {}
def fetch(self, query: str) -> list[str]:
return self._cache.get(query, [])python
from typing import ClassVar
class Repository:
default_limit: ClassVar[int] = 100
def __init__(self, name: str, url: str) -> None:
self.name = name
self.url = url
self._cache: dict[str, list[str]] = {}
def fetch(self, query: str) -> list[str]:
return self._cache.get(query, [])TypedDict for Structured Dicts
结构化字典的TypedDict
Use instead of for known-structure dictionaries:
TypedDictdict[str, Any]python
from typing import TypedDict
class UserRecord(TypedDict):
id: int
name: str
email: str
class PartialUser(TypedDict, total=False):
nickname: str
avatar_url: str
def create_user(data: UserRecord) -> None:
print(data["name"]) # mypy knows this is str对于已知结构的字典,使用替代:
TypedDictdict[str, Any]python
from typing import TypedDict
class UserRecord(TypedDict):
id: int
name: str
email: str
class PartialUser(TypedDict, total=False):
nickname: str
avatar_url: str
def create_user(data: UserRecord) -> None:
print(data["name"]) # mypy知道此处为str类型Protocols for Duck Typing
鸭子类型的Protocol
Prefer over concrete base classes for flexible interfaces:
Protocolpython
from typing import Protocol
class Closeable(Protocol):
def close(self) -> None: ...
class Readable(Protocol):
def read(self, n: int = -1) -> bytes: ...
def process_stream(stream: Readable) -> bytes:
return stream.read()对于灵活的接口,优先使用而非具体基类:
Protocolpython
from typing import Protocol
class Closeable(Protocol):
def close(self) -> None: ...
class Readable(Protocol):
def read(self, n: int = -1) -> bytes: ...
def process_stream(stream: Readable) -> bytes:
return stream.read()Strictness Levels
严格性级别
Adopt strictness incrementally. Start permissive, tighten over time.
逐步提升严格性。从宽松模式开始,随着时间推移逐步收紧。
Recommended Progression
推荐进阶路径
Level 1 — New project baseline ():
pyproject.tomltoml
[tool.mypy]
python_version = "3.12"
warn_return_any = true
warn_unused_configs = true
warn_unused_ignores = trueLevel 2 — Growing codebase:
toml
[tool.mypy]
python_version = "3.12"
warn_return_any = true
warn_unused_configs = true
warn_unused_ignores = true
disallow_incomplete_defs = true
check_untyped_defs = trueLevel 3 — Strict (production-ready):
toml
[tool.mypy]
python_version = "3.12"
strict = true
warn_unused_ignores = truestrictdisallow_untyped_defsdisallow_any_genericswarn_return_anyno_implicit_reexportstrict_equality级别1 — 新项目基准():
pyproject.tomltoml
[tool.mypy]
python_version = "3.12"
warn_return_any = true
warn_unused_configs = true
warn_unused_ignores = true级别2 — 增长中的代码库:
toml
[tool.mypy]
python_version = "3.12"
warn_return_any = true
warn_unused_configs = true
warn_unused_ignores = true
disallow_incomplete_defs = true
check_untyped_defs = true级别3 — 严格模式(生产就绪):
toml
[tool.mypy]
python_version = "3.12"
strict = true
warn_unused_ignores = truestrictdisallow_untyped_defsdisallow_any_genericswarn_return_anyno_implicit_reexportstrict_equalityHandling Third-Party Libraries
第三方库处理
Install Type Stubs
安装类型存根
bash
undefinedbash
undefinedCheck if stubs are available
检查是否有可用存根
mypy --install-types
mypy --install-types
Install specific stubs
安装特定存根
pip install types-requests types-PyYAML types-redis
undefinedpip install types-requests types-PyYAML types-redis
undefinedSuppress Missing Stubs Per Module
按模块抑制缺失存根的错误
Avoid global . Scope it to specific libraries:
ignore_missing_importstoml
undefined避免全局设置,将其限定在特定库:
ignore_missing_importstoml
undefinedpyproject.toml — preferred approach
pyproject.toml — 推荐方式
[[tool.mypy.overrides]]
module = ["boto3.", "botocore.", "some_untyped_lib"]
ignore_missing_imports = true
undefined[[tool.mypy.overrides]]
module = ["boto3.", "botocore.", "some_untyped_lib"]
ignore_missing_imports = true
undefinedInline Suppression (Use Sparingly)
行内抑制(谨慎使用)
python
import untyped_lib # type: ignore[import-untyped]
result = complex_dynamic_call() # type: ignore[no-any-return] # reason: third-party returns AnyAlways add a comment explaining why the suppression is necessary.
python
import untyped_lib # type: ignore[import-untyped]
result = complex_dynamic_call() # type: ignore[no-any-return] # 原因:第三方库返回Any类型务必添加注释说明抑制错误的必要性。
Common Use Cases
常见使用场景
Migrating an Existing Codebase
迁移现有代码库
Start with zero annotations and progressively type the codebase:
- Run — establish a zero-error baseline.
mypy --ignore-missing-imports src/ - Enable to catch bugs inside unannotated functions.
check_untyped_defs = true - Add annotations to public API functions first (highest value).
- Enable to prevent partially-annotated functions.
disallow_incomplete_defs - Gradually enable per package via
disallow_untyped_defs.[[tool.mypy.overrides]] - Reach as the final goal.
strict = true
toml
undefined从无注解开始,逐步为代码库添加类型注解:
- 运行—— 建立零错误基准。
mypy --ignore-missing-imports src/ - 启用以捕获未注解函数内部的bug。
check_untyped_defs = true - 优先为公共API函数添加注解(价值最高)。
- 启用以避免部分注解的函数。
disallow_incomplete_defs - 通过按包逐步启用
[[tool.mypy.overrides]]。disallow_untyped_defs - 最终目标是启用。
strict = true
toml
undefinedMigrate package-by-package
按包逐步迁移
[[tool.mypy.overrides]]
module = "myapp.core.*"
disallow_untyped_defs = true
[[tool.mypy.overrides]]
module = "myapp.legacy.*"
ignore_errors = true # deal with later
undefined[[tool.mypy.overrides]]
module = "myapp.core.*"
disallow_untyped_defs = true
[[tool.mypy.overrides]]
module = "myapp.legacy.*"
ignore_errors = true # 后续处理
undefinedFastAPI / Pydantic Integration
FastAPI / Pydantic集成
python
from pydantic import BaseModel
class Item(BaseModel):
name: str
price: float
tags: list[str] = []python
from pydantic import BaseModel
class Item(BaseModel):
name: str
price: float
tags: list[str] = []FastAPI + mypy works seamlessly — Pydantic models are fully typed
FastAPI + mypy无缝协作 —— Pydantic模型是完全类型化的
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def get_item(item_id: int) -> Item:
return Item(name="Widget", price=9.99)
undefinedfrom fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def get_item(item_id: int) -> Item:
return Item(name="Widget", price=9.99)
undefinedSQLAlchemy with mypy Plugin
结合mypy插件的SQLAlchemy
toml
[tool.mypy]
plugins = ["sqlalchemy.ext.mypy.plugin"]python
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = "users"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str]
email: Mapped[str | None]toml
[tool.mypy]
plugins = ["sqlalchemy.ext.mypy.plugin"]python
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = "users"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str]
email: Mapped[str | None]Type Narrowing
类型收窄
Mypy understands , , and guard patterns:
isinstanceassertpython
def render(value: str | int | None) -> str:
if value is None:
return ""
if isinstance(value, int):
return str(value)
return value.upper() # mypy knows: value is str hereUse during development to inspect inferred types:
reveal_type()python
x = [1, 2, 3]
reveal_type(x) # Revealed type is "builtins.list[builtins.int]"Mypy支持、和守卫模式:
isinstanceassertpython
def render(value: str | int | None) -> str:
if value is None:
return ""
if isinstance(value, int):
return str(value)
return value.upper() # mypy知道:此处value为str类型开发期间使用检查推断的类型:
reveal_type()python
x = [1, 2, 3]
reveal_type(x) # 显示类型为 "builtins.list[builtins.int]"CI Integration
CI集成
Pre-commit Hook
预提交钩子
yaml
undefinedyaml
undefined.pre-commit-config.yaml
.pre-commit-config.yaml
repos:
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.9.0
hooks:
- id: mypy
additional_dependencies:
- types-requests
- pydantic
- id: mypy
additional_dependencies:
undefinedrepos:
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.9.0
hooks:
- id: mypy
additional_dependencies:
- types-requests
- pydantic
- id: mypy
additional_dependencies:
undefinedGitHub Actions
GitHub Actions
yaml
- name: Run mypy
run: mypy src/ --config-file pyproject.tomlyaml
- name: Run mypy
run: mypy src/ --config-file pyproject.tomlQuick Reference
速查参考
| Pattern | Syntax |
|---|---|
| Basic function | |
| Optional param | |
| List of strings | |
| Dict | |
| Callable | |
| Any iterable | |
| Typed dict | |
| Protocol | |
| Suppress line | |
| Debug type | |
| Forward ref | |
| Flag | Purpose |
|---|---|
| Enable all optional checks |
| Require all function annotations |
| Check bodies of unannotated functions |
| Warn on implicit |
| Catch stale |
| Suppress missing stub errors |
| 模式 | 语法 |
|---|---|
| 基础函数 | |
| 可选参数 | |
| 字符串列表 | |
| 字典 | |
| 可调用对象 | |
| 任意可迭代对象 | |
| 类型化字典 | |
| 协议 | |
| 行内抑制 | |
| 调试类型 | |
| 前向引用 | |
| 标志 | 用途 |
|---|---|
| 启用所有可选检查 |
| 要求所有函数添加注解 |
| 检查未注解函数的函数体 |
| 对隐式返回Any类型发出警告 |
| 捕获过时的 |
| 抑制缺失存根的错误 |
Additional Resources
额外资源
For complete configuration options and advanced patterns:
- — Complete
references/configuration-guide.mdtemplates and per-module override patternspyproject.toml - — Generics, Protocols, TypeVar, ParamSpec, overloads, and advanced patterns
references/type-patterns.md - — Ready-to-use configuration for new and migrating projects
examples/pyproject.toml
如需完整配置选项和进阶模式:
- —— 完整的
references/configuration-guide.md模板和按模块覆盖的模式pyproject.toml - —— 泛型、Protocol、TypeVar、ParamSpec、重载及进阶模式
references/type-patterns.md - —— 适用于新项目和迁移项目的即用型配置
examples/pyproject.toml