正确顺序只能是:autoflake → isort → black,因autoflake删未用代码、isort重排import、black统一格式,顺序颠倒会导致重复操作或语法错误。

pre-commit 配置里 black、isort、autoflake 的执行顺序为什么重要
三者都改代码格式,但改的不是同一层:autoflake 删未用 import 和变量,isort 重排 import 顺序,black 统一缩进/换行/空格。如果顺序反了,比如 isort 在 autoflake 前跑,就可能把 autoflake 即将删掉的 import 又按规则排一遍,白忙活;更糟的是 black 可能格式化完,autoflake 又删掉某行导致语法错误(比如删了唯一引用的 from typing import Optional 后,Optional[str] 报错)。
正确顺序只能是:autoflake → isort → black。pre-commit 按配置文件中 hooks 的书写顺序执行,所以必须严格按这个顺序写。
- autoflake 要加
--in-place --remove-all-unused-imports --remove-unused-variables,否则默认只打印不修改 - isort 需显式指定
profile: black或等效配置(如multi_line_output: 3),否则和 black 冲突 - black 不需要额外参数,但注意它默认不处理
.pyi文件,如有需求得加types: [python, pyi]
autoflake 报错 “No module named 'autoflake'” 却已 pip install
pre-commit 自带独立虚拟环境,不复用你当前 shell 的 Python 环境。即使你在全局或 venv 里装了 autoflake,pre-commit 还是会自己拉一个干净环境并只装它配置里声明的依赖。
所以必须在 .pre-commit-config.yaml 的对应 hook 下,明确写上 additional_dependencies:
立即学习“Python免费学习笔记(深入)”;
repos:
- repo: https://github.com/myint/autoflake
rev: v2.2.1
hooks:
- id: autoflake
args: [--in-place, --remove-all-unused-imports, --remove-unused-variables]
additional_dependencies: [autoflake==2.2.1]漏掉 additional_dependencies 是最常见原因。版本号建议锁死,避免某天 CI 突然失败。
- black 和 isort 同理,也要各自配
additional_dependencies,哪怕它们的 repo 地址本身带依赖声明 - pre-commit install 之后,可用
pre-commit run --all-files手动触发一次,看是否还报 import 错误 - 如果用 pyproject.toml 管理依赖,pre-commit 仍不会自动读取,必须显式声明
isort 和 black 在 type hint 上打架怎么办
典型现象:isort 把 from __future__ import annotations 排到 import 块最顶,black 却认为它该单独成块、前面空两行——结果 pre-commit 死循环:一次提交后 isort 动了,下一次 black 又动,再下一次 isort 又动……
根本原因是 isort 默认不识别 from __future__ 的特殊性,而 black 的格式规则又和 isort 的 import 分组逻辑不一致。
- 在 isort 配置里加
known_future_library: ["__future__"],让 isort 把它当一类特殊 import 处理 - 同时设
force_sort_within_sections: true,避免 isort 因“不同 section”拒绝重排 - black 侧无需改,但它要求 isort 输出必须兼容 PEP 8 + PEP 484,所以 isort 的
profile: black不能省
如果项目用 pyproject.toml,isort 配置应放在 [tool.isort] 下,并确保 multi_line_output = 3(即 black 风格的 hanging grid)。
pre-commit hook 运行太慢,尤其 autoflake 扫全量文件
autoflake 默认扫描所有 .py 文件,包括 tests/、migrations/、venv/ 甚至 .git/ 下的 Python 片段,既慢又可能误删(比如某些生成的 migration 文件里有看似未用实则必需的 import)。
关键是缩小作用范围,而不是关掉它:
- 用
types_or: [python]替代默认的types: [python],避免匹配到 .pyi/.pyw 等边缘类型 - 加
exclude: '^((tests|venv|\.git|migrations)/|.*__pycache__.*$)',正则排除高频干扰目录 - autoflake 本身支持
--exclude,但 pre-commit 的 exclude 是更前置的过滤,优先级更高、更省 CPU - 如果团队接受,可考虑去掉
--remove-unused-variables—— 它比删 import 更容易误伤(比如动态属性、debug 变量),且 black/isort 不处理它
实际测过:对 500+ 文件的项目,加 exclude 后单次 hook 从 8 秒降到 1.2 秒。慢不是预提交的宿命,是没筛干净。
复杂点在于,exclude 规则要和团队 IDE 设置、CI 路径保持一致;最容易被忽略的是 migrations/ 目录——Django 用户几乎必踩这个坑。










