一、Python开发者的"工具地狱"
如果你维护过一个中大型Python项目,大概率经历过这样的场景:flake8 做静态检查,black 管格式化,isort 理导入顺序,pydocstyle 查文档字符串,pyupgrade 做语法现代化升级,autoflake 清未使用的导入……一个 pre-commit 钩子里塞了五六种工具,CI 流水线跑一次代码检查要等几十秒甚至几分钟,本地改一行代码按下保存后,等着各种工具排队运行。
这还不算版本兼容问题。flake8 和 black 偶尔对同一行代码有不同看法,配置项散落在 setup.cfg、pyproject.toml、.flake8 三个文件里,改一条规则要在好几个地方同步。新成员入职,光配开发环境就要折腾半小时。
有没有一个工具能把这些全干掉,还比它们加起来快100倍?
这就是 Ruff。
二、Ruff 是什么
Ruff 是 Astral 公司用 Rust 写的高性能 Python linter 和 formatter,开源(MIT 协议),2022 年发布至今 GitHub star 数已超 35k。它要解决的核心问题很直白:你不再需要 flake8、black、isort、pydocstyle、pyupgrade、autoflake 中的任何一个,一个 ruff 命令全部搞定,而且快到让你怀疑它到底有没有在干活。
FastAPI 创始人 Sebastián Ramírez 的原话是:"Ruff is so fast that sometimes I intentionally introduce an error just to make sure it's still running."
三、核心优势拆解
3.1 性能:碾压级的快
Ruff 到底有多快?看一组实测对比(项目:Django 源码,约 60 万行 Python):
| 工具 | 单次扫描耗时 | 相对 Ruff 的倍数 |
|---|
| Ruff | 0.12 秒 | 1x |
| Flake8 | 14.3 秒 | ~120x |
| Pylint | 42.8 秒 | ~357x |
| Black(格式化) | 2.1 秒 | ~18x |
| Ruff formatter | 0.18 秒 | 1x |
Dagster 创始人 Nick Schrock 分享过:在他们 25 万行的代码库上,Pylint 需要 2.5 分钟,Ruff 只用0.4 秒。
快的秘密有两个层面:
- 语言层面:Rust 零成本抽象 + 无 GC + 编译到原生代码,直接避免了 Python 解释器开销。Flake8 底层其实是 Python 进程,每个检查插件都在 Python 虚拟机里跑一遍 AST,而 Ruff 在 Rust 里一次性构建 AST 后批量执行所有规则。
- 架构层面:增量缓存 + 多线程并行。改了一个文件只检查那一个,没改的直接读缓存跳过。配合 --watch 模式,每次保存瞬间出结果。
3.2 规则库:800+ 条开箱即用
Ruff 重新实现了几乎所有主流 Flake8 插件的规则,按字母前缀分类:
| 前缀 | 来源/类别 | 规则数 | 举例 |
|---|
| E/W | pycodestyle | 71 | E501(行太长) |
| F | Pyflakes | 58 | F841(未使用变量) |
| B | flake8-bugbear | 68 | B006(可变默认参数) |
| I | isort | 20 | I001(导入顺序) |
| SIM | flake8-simplify | 30 | SIM108(用三元表达式) |
| UP | pyupgrade | 46 | UP006(用 list 替代 typing.List) |
| N | pep8-naming | 32 | N801(类名应大写开头) |
| D | pydocstyle | 70 | D100(模块缺文档字符串) |
你可以按需启用:想要严格的类型注解检查?加 ANN。想做安全审计?加 S(bandit)。想强制写 docstring?加 D。一条 select 配置搞定,不用装七个插件。
3.3 自动修复能力
Ruff 不是"只告诉你哪里错了"的唠叨工具。大量规则支持 --fix 自动修复,而且分两个安全等级:
- 安全修复(safe fix):绝对不会改变代码语义。比如删掉未使用的导入 import os、把 list() 改成 []、修复缩进对齐。
- 不安全修复(unsafe fix):可能会改变行为,需要你确认。比如删除未使用的变量 x = expensive_call()——删了变量,函数调用也不执行了。
运行 ruff check --fix 只应用安全修复;加上 --unsafe-fixes 才上第二档。这个设计很聪明:你可以在 CI 里只跑安全修复,在本地手动确认后再跑不安全修复。
3.4 统一格式化器
v0.1.0 起 Ruff 内置了自己的格式化器,目标是 99.9% 兼容 Black 的输出风格,同时快 10-30 倍。关键特性:
- 与 linter 共享配置:不会出现"linter 说要这样、formatter 偏要那样"的冲突。因为两个功能跑在同一套 AST 上。
- 2026 Style Guide:v0.15.0 引入了更激进的格式化风格(如 lambda 体自动加括号、Python 3.14+ 的 except 元组去括号),向前兼容未来 Python 语法。
- 行宽、引号风格、缩进等全部可配置,行为与 Black 一致但更多控制权。
3.5 编辑器集成体验
VS Code 官方扩展 charliermarsh.ruff 在保存时自动运行 Ruff,错误红色波浪线 + 一键修复。JetBrains 系(PyCharm)、Neovim、Emacs 也都有成熟集成。
最直观的感受:保存文件后 100ms 内,IDE 里所有格式问题和 lint 警告全部更新。不再像以前用 flake8 那样,改完一行等两秒才看到红线冒出。
四、适用场景
场景一:新项目一杆到底
从项目第一天就把 Ruff 引入,配置好 pyproject.toml,pre-commit 一挂,团队成员零成本上手。
场景二:老项目迁移"剃头"
接手一个几万行的老代码库,代码风格参差不齐。用 Ruff 的 --fix 一次性批量修复,再配置 CI 阻止新增问题。迁移成本极低:在 pyproject.toml 里加一段配置,CI 脚本里加一行 ruff check。
场景三:Monorepo 分层管理
Ruff 支持分层配置。根目录一个宽松的 ruff.toml,子包(如 src/api/ruff.toml、src/cli/ruff.toml)可以覆盖或收紧规则。每个团队管自己的风格,互不打架。
场景四:CI/CD 快速门禁
把你的 CI lint 步骤从 30 秒缩减到 0.5 秒。对频繁提交的分支来说,这个差距会滚雪球式放大。配上一个 --exit-zero,甚至可以在 PR 评论里"建议式"提示而非硬性阻断。
场景五:pre-commit 钩子零感知
# .pre-commit-config.yaml repos: - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.15.0 hooks: - id: ruff args: [--fix] - id: ruff-formatgit commit 时自动运行,快到你感觉不到它的存在——不再有"提交代码先去倒杯水"的体验。
五、从零上手:10 分钟配置指南
5.1 安装
Ruff 是单个二进制,安装方式非常多:
# 推荐:通过 uv 安装(uv 也是 Astral 出品,Python 包管理器) uv tool install ruff@latest # 传统方式 pip install ruff # 给项目加开发依赖 uv add --dev ruff # macOS/Linux 直接装二进制 brew install ruff # Windows powershell -c "irm https://astral.sh/ruff/install.ps1 | iex"验证:
ruff --version # ruff 0.15.05.2 最小化配置
在项目根目录创建 ruff.toml(也可以写在 pyproject.toml 的 [tool.ruff] 下):
# ruff.toml # 目标 Python 版本 target-version = "py312" # 行宽(与 Black 一致) line-length = 100 # ──── Linter 配置 ──── [lint] # 启用哪些规则组 select = [ "E", # pycodestyle 错误 "W", # pycodestyle 警告 "F", # Pyflakes "B", # flake8-bugbear "I", # isort(导入排序) "N", # pep8-naming(命名规范) "UP", # pyupgrade(语法现代化) "SIM", # flake8-simplify(简化建议) "C4", # flake8-comprehensions ] # 忽略特定规则(按项目需要调整) ignore = [ "E501", # 行太长(交给 formatter 处理) ] # ──── Formatter 配置 ──── [format] quote-style = "double" indent-style = "space" docstring-code-format = true5.3 常用命令速查
# Lint 检查 ruff check # 检查当前目录 ruff check --fix # 自动修复 ruff check --fix --unsafe-fixes # 含不安全修复 ruff check --watch # 监听模式,文件变动自动检查 ruff check --statistics # 按规则统计问题数量 # 格式化 ruff format # 格式化当前目录 ruff format --check # 仅检查,不修改(CI 用) ruff format --diff # 显示差异不应用 # 查看某条规则的说明 ruff rule E501 # 查看 E501 详情 # 仅检查指定文件/目录 ruff check src/models/user.py ruff check src/5.4 实战工作流
日常开发:配好 VS Code 扩展 + ruff.toml,保存即检查。
提交前:运行 ruff check --fix && ruff format,自动化清理。
CI 流水线(GitHub Actions 示例):
name: Lint on: [push, pull_request] jobs: ruff: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: astral-sh/ruff-action@v3 with: args: "check" - uses: astral-sh/ruff-action@v3 with: args: "format --check"5.5 渐进式迁移:从 Flake8+Black 迁到 Ruff
如果你已有项目在用 Flake8 + Black + isort,迁移分三步走:
第一步:对齐规则
# 先生成当前 flake8 正在使用的规则列表 flake8 --select=E,W,F,B --format=json . > old_issues.json # 用 ruff check --statistics 对比差异 ruff check --statistics把差异规则按需加入 ignore 或 select。
第二步:一次性批量修复
ruff check --fix --unsafe-fixes # 先修 lint ruff format # 再格式化建议在一个独立分支上执行,方便 code review 对比 diff。
第三步:替换 CI 和 pre-commit
删掉 .flake8、pyproject.toml 里的 isort 配置,把 CI 脚本里的 flake8 + black --check + isort --check 换成两行 ruff check + ruff format --check。
迁移完成后的收益非常直观:以 Django 规模的项目为例,CI lint 步骤从~22 秒降至 ~0.3 秒。
六、Ruff vs 同类方案
| 维度 | Ruff | Flake8 + 插件 | Black + isort + Pylint |
|---|
| 安装复杂度 | 单二进制 | 5-10 个 pip 包 | 3 个 pip 包 |
| 配置文件 | 1个 toml | setup.cfg + .flake8 + tox.ini | pyproject.toml + .pylintrc |
| Lint 速度(Django 规模) | 0.12s | 14s | 42s |
| Formatter 速度 | 0.18s | 不适用 | 2.1s(仅 Black) |
| 内置规则数 | 800+ | 100+(基础) | 400+ |
| 自动修复 | 安全/不安全双档 | 有限 | 有限 |
| 规则冲突处理 | 无(同 AST) | 常有 | 常有 |
| 编辑器体验 | 保存即检查 | 有延迟 | 明显延迟 |
| 社区生态 | 快速增长 | 成熟但停滞 | 成熟 |
七、实践建议与注意事项
建议
新项目直接上 Ruff——没有历史包袱,一开始就严格配置 select,养成好习惯。
老项目用 --fix 一次性剃头,然后在 CI 中只跑 ruff check(不加 --fix),阻断新增问题。
善用 per-file-ignores。比如测试文件里放宽某些规则:
[lint.per-file-ignores] "tests/**/*.py" = ["D100", "S101"] # 测试不需要模块文档字符串,允许 assert配合 uv 做全链路 Rust 化:uv 管理依赖 + Ruff 管理代码质量,两个工具都来自 Astral,协作零摩擦。
注意事项
- Ruff 的规则实现是"重新实现"而非"调用原版",极少数边界情况可能与 Flake8 行为有微小差异。迁移后建议跑一轮完整对比。
- Formatter 稳定版已发布(v0.1.0 起),但不保证与 Black 的每一个空格位置完全一致。对格式极其敏感的场景,先用 ruff format --diff 预览。
- 部分冷门 Flake8 插件尚未被 Ruff 重写。如果你的项目严重依赖某个小众插件,先检查 Ruff 是否已覆盖对应规则前缀。
Ruff 用了三年时间(2022-2025)从"又一个 linter"成长为 Python 代码质量的事实标准工具链。它证明了"用 Rust 重写 Python 工具"不是噱头,而是从架构层面真正改变了开发者的日常体验——把原本需要排队等十几秒的检查压缩到在你松开拓键之前就已完成。如果你还没试过,给你的主项目跑一次 pip install ruff && ruff check --statistics,看看它会检出什么,大概率你会立刻把 .flake8 删掉。