Python black + isort + autoflake 的 pre-commit 链

1次阅读

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

Python black + isort + autoflake 的 pre-commit 链

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 用户几乎必踩这个坑。

text=ZqhQzanResources