2026 年,Ruff 在 GitHub 上突破 45,000 Stars,成为 Python 生态中增长最快的开发者工具。它用 Rust 重写了 Python 社区过去十年积累的 linter 和 formatter 生态——单个工具替代 flake8、black、isort、pylint、pyupgrade、autoflake 六个工具,速度提升 10-100 倍。如果你还在用多个工具组合来保持 Python 代码质量,Ruff 将彻底改变你的开发体验。
🚀 一、为什么 Python 社区需要 Ruff
1.1 传统 Python 工具链的痛点
在 Ruff 出现之前,一个中大型 Python 项目的工具链通常长这样:
# ❌ 传统方案:6 个独立工具,各自独立安装和配置
pip install flake8 black isort pylint pyupgrade autoflake
flake8 src/ --max-line-length=88
black src/ --check
isort src/ --check-only --profile=black
pylint src/ --disable=C0114,C0115
pyupgrade --py312-plus src/**/*.py
autoflake --in-place --remove-all-unused-imports src/**/*.py
这个方案有三个致命问题:
- ❌ 速度慢——对一个 500 文件的中型项目,完整 lint 需要 30-60 秒
- ❌ 配置碎片化——每个工具有自己的配置文件(
.flake8、pyproject.toml [tool.black]、.isort.cfg、.pylintrc),配置冲突频繁 - ❌ 版本地狱——工具之间依赖冲突,Python 版本兼容性不一致
⚠️ **警告:**在团队协作中,配置碎片化是代码质量下降的根本原因。当一个项目有 4 个以上 lint 配置文件时,新成员几乎不可能正确配置开发环境。
1.2 Ruff 的核心设计理念
Ruff 由 Charlie Marsh(Astral 创始人,同时也是 uv 的开发者)在 2022 年启动,核心理念很简单:用 Rust 实现一个统一的、超高速的 Python 代码分析工具。
Ruff 的技术架构有三个关键设计:
| 设计决策 | 传统工具 | Ruff | 影响 |
|---|---|---|---|
| 实现语言 | Python | Rust | 单线程快 10x,多线程快 100x |
| 解析方式 | AST 遍历 | 增量式 CST 解析 | 支持增量检查、错误恢复 |
| 规则系统 | 独立插件 | 统一规则引擎 | 700+ 规则零配置启用 |
| 配置管理 | 多文件分散 | 单一 pyproject.toml |
一个文件搞定一切 |
| 自动修复 | 部分支持 | 内置 unsafe fixes | 一键修复大部分问题 |
下面这张性能对比数据来自 Ruff 官方基准测试(500 个 Python 文件,约 10 万行代码):
| 工具 | 单线程耗时 | 多线程耗时 | 相对速度 |
|---|---|---|---|
| flake8 | 12.3s | N/A | 基准 1x |
| pylint | 45.6s | N/A | 0.27x |
| ruff check | 0.15s | 0.08s | 154x |
| black | 8.7s | N/A | 基准 1x |
| ruff format | 0.22s | 0.12s | 72x |
⚡ **关键结论:**Ruff 的速度优势不是微优化,而是量级跨越。在 CI/CD Pipeline 中,这意味着从"分钟级等待"变成"秒级反馈"。
🔧 二、Ruff 实战:从安装到生产配置
2.1 安装与基础配置
# ✅ 推荐:使用 uv 安装(同样是 Astral 出品,速度最快)
uv tool install ruff
# 或者使用 pipx
pipx install ruff
# 或者直接用 pip
pip install ruff
# 验证安装
ruff version
# ruff 0.11.13
在项目根目录的 pyproject.toml 中配置 Ruff:
# pyproject.toml — Ruff 完整配置示例
[tool.ruff]
# 目标 Python 版本
target-version = "py312"
# 行宽设置(与 black 默认值一致)
line-length = 88
# 排除目录
exclude = [
".git",
".venv",
"__pycache__",
"build",
"dist",
"migrations",
"*.egg-info",
]
[tool.ruff.lint]
# 启用的规则集
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"N", # pep8-naming
"UP", # pyupgrade
"YTT", # flake8-2020
"B", # flake8-bugbear
"A", # flake8-builtins
"C4", # flake8-comprehensions
"DTZ", # flake8-datetimez
"T10", # flake8-debugger
"EM", # flake8-errmsg
"ISC", # flake8-implicit-str-concat
"ICN", # flake8-import-conventions
"PIE", # flake8-pie
"PT", # flake8-pytest-style
"RSE", # flake8-raise
"RET", # flake8-return
"SIM", # flake8-simplify
"TID", # flake8-tidy-imports
"TCH", # flake8-type-checking
"ARG", # flake8-unused-arguments
"PTH", # flake8-use-pathlib
"RUF", # Ruff 专属规则
]
# 忽略的规则
ignore = [
"E501", # 行长度由 formatter 处理
"B008", # 函数参数默认值中的函数调用
"SIM108", # 三元表达式(可读性优先)
]
# 允许自动修复
fixable = ["ALL"]
[tool.ruff.lint.per-file-ignores]
# 测试文件放宽规则
"tests/**/*.py" = ["S101", "ARG001", "ANN201", "PLR2004"]
# 脚本文件允许 print
"scripts/**/*.py" = ["T201"]
# __init__.py 允许未使用的导入(re-exports)
"__init__.py" = ["F401"]
[tool.ruff.lint.isort]
# isort 兼容配置
known-first-party = ["myproject"]
force-single-line = false
lines-after-imports = 2
[tool.ruff.format]
# formatter 配置
quote-style = "double"
indent-style = "space"
skip-magic-trailing-comma = false
line-ending = "auto"
💡 **提示:**Ruff 的所有配置都集中在
pyproject.toml中,不再需要.flake8、.isort.cfg、.pylintrc等多个配置文件。这是 Ruff 带来的最大工程化收益之一。
2.2 日常使用命令
# 检查代码(等价于 flake8 + isort --check + pylint)
ruff check src/
# 检查并自动修复可修复的问题
ruff check --fix src/
# 包含 unsafe 修复(更激进,建议先 dry-run)
ruff check --fix --unsafe-fixes src/
# 格式化代码(等价于 black)
ruff format src/
# 格式化检查(CI 中使用,不修改文件)
ruff format --check src/
# 仅检查特定规则
ruff check --select I src/ # 只检查 import 排序
ruff check --select E,W src/ # 只检查 pycodestyle
# 查看某条规则的详细说明
ruff rule B007
# B007: Unused loop control variable (use `_` prefix)
# 列出所有可用规则
ruff rule --all | wc -l
# 700+ rules available
2.3 CI/CD 集成方案
下面是一个完整的 GitHub Actions 配置,将 Ruff 集成到 CI Pipeline:
# .github/workflows/lint.yml — GitHub Actions Ruff CI 配置
name: Code Quality
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
ruff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v5
with:
version: "latest"
- name: Install Ruff
run: uv tool install ruff
- name: Ruff lint check
run: ruff check --output-format=github .
- name: Ruff format check
run: ruff format --check .
- name: Run tests
run: |
uv sync
uv run pytest tests/ -x -q
📌 **记住:**在 CI 中始终使用
ruff format --check而不是ruff format。前者只检查不修改(失败即阻断),后者会修改代码(CI 中无意义)。lint 同理,用ruff check而不是ruff check --fix。
💡 三、从传统工具迁移到 Ruff
3.1 flake8 + black + isort → Ruff 迁移
迁移分三步走,建议分三个 PR 完成,避免一次性大量改动:
第一步:添加 Ruff 并配置等价规则
# 生成当前 flake8 使用的规则映射
pip install flake8
flake8 src/ --select=E,W,F 2>&1 | cut -d: -f4 | sort | uniq -c | sort -rn
# 安装 ruff 并验证规则覆盖
pip install ruff
ruff check src/ --select=E,W,F,I,N,UP,B
第二步:规则映射表
| 原工具 | 配置 | Ruff 等价配置 |
|---|---|---|
flake8 E,W,F |
.flake8 |
select = ["E", "W", "F"] |
flake8 max-line-length=88 |
.flake8 |
line-length = 88 |
flake8 ignore=E501,W503 |
.flake8 |
ignore = ["E501", "W503"] |
black line-length=88 |
pyproject.toml [tool.black] |
line-length = 88 |
isort profile=black |
.isort.cfg |
[tool.ruff.lint.isort] section |
pylint disable=C0114 |
.pylintrc |
ignore = ["ANN201"] |
pyupgrade --py312-plus |
CLI flag | select = ["UP"] + target-version = "py312" |
第三步:替换工具链
# ❌ 删除旧工具配置文件
rm .flake8 .isort.cfg .pylintrc setup.cfg
# 从 pyproject.toml 删除 [tool.black]、[tool.isort] 等段落
# ✅ 只保留 Ruff 配置
# 在 pyproject.toml 中添加 [tool.ruff] 段落
# CI 中替换命令
- flake8 src/
- black --check src/
- isort --check-only src/
+ ruff check src/
+ ruff format --check src/
3.2 常见迁移陷阱
陷阱 1:black 和 Ruff Format 的细微差异
Ruff formatter 设计目标是 99% 与 black 兼容,但存在一些边缘差异:
# black 格式化结果
result = {
"key": value,
"another_key": another_value_with_a_very_long_name,
}
# Ruff format 可能在某些边缘情况下不同(主要是 magic trailing comma 处理)
# 解决方案:第一次全量格式化后提交一个专门的格式化 PR
ruff format src/
git add -A && git commit -m "style: migrate to ruff format"
⚠️ **警告:**迁移时第一次运行
ruff format会产生大量格式变更。建议在一个独立的 PR 中完成格式迁移,并将其添加到.git-blame-ignore-revs文件中,避免污染 git blame 历史。
# 生成 .git-blame-ignore-revs
echo "# Ruff format migration" > .git-blame-ignore-revs
git log --oneline -1 --format="%H" >> .git-blame-ignore-revs
# 告诉 git 忽略这个 commit
git config blame.ignoreRevsFile .git-blame-ignore-revs
陷阱 2:isort 的 known-first-party 配置
# ❌ 错误:忘记配置 known-first-party,导致项目内部包被归类为第三方
[tool.ruff.lint.isort]
# isort 自动推断,但 Ruff 需要显式配置
# ✅ 正确:明确告知 Ruff 哪些是项目内部包
[tool.ruff.lint.isort]
known-first-party = ["myproject", "myproject_core"]
force-sort-within-sections = true
陷阱 3:pylint 的规则命名差异
# pylint 的 C0115 (missing-class-docstring) 在 Ruff 中对应:
# D101 (pydocstyle: missing docstring in public class)
# pylint 的 W0611 (unused-import) 在 Ruff 中对应:
# F401 (pyflakes: unused import)
# 使用 ruff rule 查看规则映射
ruff rule F401
📊 四、Ruff 高级功能与实战技巧
4.1 Unsafe Fixes:自动重构利器
Ruff 的 unsafe fixes 功能可以自动执行一些"可能改变语义"的修复:
# 查看有哪些 unsafe fixes 可用
ruff check --unsafe-fixes --diff src/
# 应用 unsafe fixes
ruff check --fix --unsafe-fixes src/
常见的 unsafe fixes 包括:
| 规则 | 修复前 | 修复后 | 风险 |
|---|---|---|---|
| UP015 | open("f", "r") |
open("f") |
极低 |
| SIM108 | if x: y = a\nelse: y = b |
y = a if x else b |
低(可读性争议) |
| B007 | for i in items: ... |
for _item in items: ... |
极低 |
| C416 | [x for x in items] |
list(items) |
极低 |
| RUF007 | zip(a, b) pairwise |
itertools.pairwise(a) |
中(Python 3.10+) |
💡 **提示:**建议在 CI 中只用
ruff check --fix(safe fixes),在本地开发中手动审查并使用--unsafe-fixes。unsafe fixes 可能改变代码行为,需要人工审查。
4.2 规则分层策略
不同项目需要不同的规则严格程度。以下是三种推荐的规则分层方案:
# 方案 A:初创项目(宽松,快速迭代)
[tool.ruff.lint]
select = ["E", "F", "W", "I", "UP", "B"]
ignore = ["E501"]
# 方案 B:中型项目(标准,平衡质量和速度)
[tool.ruff.lint]
select = ["E", "F", "W", "I", "N", "UP", "B", "A", "C4", "SIM", "TCH", "RUF"]
ignore = ["E501", "SIM108"]
# 方案 C:大型项目/开源项目(严格,全面检查)
[tool.ruff.lint]
select = ["E", "F", "W", "I", "N", "UP", "YTT", "B", "A", "C4", "DTZ",
"T10", "EM", "ISC", "ICN", "PIE", "PT", "RSE", "RET", "SIM",
"TID", "TCH", "ARG", "PTH", "RUF", "D", "ANN", "S", "FBT",
"COM", "PL", "TRY", "PERF", "FURB", "LOG", "Q"]
ignore = ["E501", "ANN101", "ANN401", "D107", "S101"]
4.3 编辑器集成
// VS Code settings.json — Ruff 扩展配置
{
"[python]": {
"editor.defaultFormatter": "charliermarsh.ruff",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.ruff": "explicit",
"source.organizeImports.ruff": "explicit"
}
},
"ruff.lint.run": "onSave",
"ruff.configurationPath": "./pyproject.toml"
}
📌 **记住:**使用 Ruff 扩展后,应该禁用 Pylint、Flake8、Black、isort 等 VS Code 扩展,避免重复检查和格式冲突。
4.4 与 pre-commit 集成
# .pre-commit-config.yaml — 使用 Ruff 官方 pre-commit hooks
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.11.13
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- id: ruff-format
这个配置在每次 git commit 时自动运行 Ruff 检查和格式化,确保进入仓库的代码始终符合规范。
⚠️ 五、Ruff 的局限性与避坑指南
5.1 Ruff 暂不支持的场景
| 场景 | 替代方案 | 原因 |
|---|---|---|
| 类型检查(type checking) | mypy / pyright / ty | 需要类型推断引擎,Ruff 专注 lint/format |
| 复杂的代码异味检测 | pylint(部分规则) | Ruff 覆盖了 80% 的 pylint 规则,但一些复杂度规则(如 C901)只提供基础支持 |
| 自定义规则开发 | pylint plugin / flake8 plugin | Ruff 的插件系统仍在开发中(见 ruff.preview) |
| Docstring 格式检查 | pydocstyle(Ruff 已支持 D 规则) | 部分 pydocstyle 规则仍在实现中 |
5.2 常见错误配置
# ❌ 错误:同时启用 black 和 ruff format(冲突)
# 不要同时安装 black 和使用 ruff format
# ❌ 错误:忽略 E501 但没有配置 formatter
# 如果你忽略 E501,必须确保 ruff format 会处理行宽
[tool.ruff.lint]
ignore = ["E501"] # OK,因为 ruff format 会处理行宽
# ❌ 错误:select 中遗漏 "I" 规则
# isort 替代必须显式启用
[tool.ruff.lint]
select = ["E", "F", "W"] # 缺少 "I",import 排序不会生效
# ✅ 正确配置
[tool.ruff.lint]
select = ["E", "F", "W", "I"] # 包含 "I"
5.3 大型 Monorepo 配置
对于 Monorepo 结构,Ruff 支持多级配置覆盖:
# 根目录 pyproject.toml — 全局默认配置
[tool.ruff]
line-length = 88
target-version = "py312"
[tool.ruff.lint]
select = ["E", "F", "W", "I", "N", "UP", "B", "RUF"]
# 子项目可以通过子目录的 pyproject.toml 或 ruff.toml 覆盖配置
# 例如 services/api/pyproject.toml 可以设置不同的规则集
# services/api/ruff.toml — API 服务的严格配置
[tool.ruff.lint]
select = ["E", "F", "W", "I", "N", "UP", "B", "RUF", "S", "ANN", "D"]
# S = security, ANN = type annotations, D = docstrings
🔍 六、实战案例:Django 项目迁移到 Ruff 全记录
6.1 迁移前后对比
以下是一个真实 Django 项目的迁移数据(237 个 Python 文件,约 2.8 万行代码):
| 指标 | 迁移前(flake8+black+isort) | 迁移后(Ruff) | 改善 |
|---|---|---|---|
| 工具数量 | 4 个独立工具 | 1 个统一工具 | -75% |
| 配置文件 | 3 个(.flake8、.isort.cfg、pyproject.toml [tool.black]) | 1 个(pyproject.toml) | -67% |
| CI lint 耗时 | 42 秒 | 0.6 秒 | 70x 加速 |
| 本地 format 耗时 | 8.5 秒 | 0.3 秒 | 28x 加速 |
| 依赖安装时间 | 15 秒(pip install 4 个包) | 2 秒(pip install ruff) | 7.5x 加速 |
| 发现的新问题 | — | 23 个此前未检测到的 bug | 额外收益 |
6.2 Ruff 发现的真实 Bug 示例
迁移过程中,Ruff 的 B(bugbear)和 RUF(Ruff 专属)规则发现了以下此前未被检测到的问题:
# Bug 1: 可变默认参数(B006 规则检测到)
# ❌ 迁移前的代码——这是一个经典的 Python 陷阱
def get_users(role, cache=[]):
cache.append(role)
return cache
# ✅ Ruff 自动修复后
def get_users(role, cache=None):
if cache is None:
cache = []
cache.append(role)
return cache
# Bug 2: 异常处理中的 continue/break 导致异常被吞掉(B012 规则)
# ❌ 迁移前的代码——异常被静默忽略,可能导致数据不一致
for item in items:
try:
process(item)
except ValueError:
continue # Ruff 警告:在 finally 块中使用 continue 会吞掉异常
# ✅ Ruff 建议的修复:显式记录被跳过的项
for item in items:
try:
process(item)
except ValueError as e:
logger.warning(f"Skipping item {item.id}: {e}")
continue
# Bug 3: 字典 key 重复(F601 规则)
# ❌ 迁移前的代码——第二个 key 覆盖了第一个,但开发者可能没注意到
config = {
"host": "localhost",
"port": 8080,
"timeout": 30,
"host": "0.0.0.0", # 覆盖了上面的 "localhost"!
}
# ✅ 修复:删除重复 key
config = {
"host": "0.0.0.0",
"port": 8080,
"timeout": 30,
}
⚡ **关键结论:**Ruff 的价值不仅在于"更快"——它内置的 700+ 规则覆盖了许多传统工具遗漏的边界情况。迁移过程中发现新 Bug 是非常常见的现象,这也是推动迁移的重要动力。
6.3 Ruff 与 pyright 配合使用的最佳实践
Ruff 不做类型检查,但可以和 pyright / mypy 完美配合。推荐的工作流是:
# 开发流程:Ruff 负责代码风格,pyright 负责类型安全
# 1. 保存时自动格式化(编辑器 Ruff 扩展)
# 2. 保存时自动 lint 修复(编辑器 Ruff 扩展)
# 3. 提交前运行类型检查(pre-commit hook)
# pre-commit 完整配置
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.11.13
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
- repo: https://github.com/microsoft/pyright-mirror
rev: v1.1.390
hooks:
- id: pyright
args: [--level, warning]
这种组合的分工非常清晰:Ruff 处理"代码看起来对不对"(风格和常见 bug),pyright 处理"代码逻辑对不对"(类型安全)。两者零冲突,因为它们检查的维度完全不同。
✅ 七、总结与最佳实践
核心建议
- ✅ 新项目直接用 Ruff——不要再安装 flake8 + black + isort 的组合
- ✅ 存量项目分步迁移——先加 lint 检查,再迁移 formatter,最后删除旧工具
- ✅ CI 中始终运行
ruff check和ruff format --check——代码质量门禁 - ✅ 配合 uv 使用——Astral 全家桶(uv + ruff)是 2026 年 Python 开发的最佳体验
- ❌ 不要用 Ruff 替代 mypy/pyright——类型检查和 lint 是两个维度,需要配合使用
- ⚠️ 迁移时务必创建独立 PR——格式化变更会污染 git blame,使用
.git-blame-ignore-revs
推荐工具链组合
| 需求 | 推荐工具 | 说明 |
|---|---|---|
| 包管理 | uv | Astral 出品,pip 的超高速替代 |
| Lint + Format | Ruff | 统一的 linter + formatter |
| 类型检查 | pyright / ty | VS Code 内置 / Astral 新项目 |
| 测试 | pytest | Python 生态标准 |
| 任务运行 | uv run + just | 依赖管理 + 任务编排 |
⚡ **关键结论:**Ruff 不仅仅是一个更快的 linter——它代表了 Python 工具链从"多个 Python 工具各自为政"到"单一 Rust 工具统一治理"的范式转变。2026 年的 Python 项目,Ruff 已经是事实标准。
相关工具推荐
- 🔧 Ruff 官方文档 — 规则参考与配置指南
- 🔧 Ruff Playground — 在线试用 Ruff 规则
- 🔧 uv — 同样由 Astral 开发的 Python 包管理器
- 🔧 Ruff VS Code 扩展 — 编辑器实时 lint
- 🔧 Ruff pre-commit hooks — Git 提交前自动检查