Ruff 是一个用 Rust 编写的极速 Python 代码检查 (Lint) 和格式化工具。它旨在提供一个高性能的替代方案,结合了 Flake8、isort、Black 等多种工具的功能,以显著提升 Python 项目的代码质量检查和格式化效率。

Ruff 的核心优势在于其极致的速度:由于底层使用 Rust 编写,它比传统的 Python 代码检查工具快 10 到 100 倍,这对于大型项目和 CI/CD 流程来说是一个巨大的改进。


一、为什么选择 Ruff?

在 Python 开发中,我们通常会使用一系列工具来维护代码质量和风格:

  • Linter (代码检查器):如 Flake8、Pylint,用于发现潜在的 bug、代码异味、不遵循最佳实践的代码。
  • Formatter (代码格式化器):如 Black、autopep8、YAPF,用于统一代码风格,使其符合 PEP 8 规范。
  • Import Sorter (导入排序器):如 isort,用于自动排序和整理 import 语句。

管理和配置这些独立的工具会增加项目的复杂性。Ruff 的出现旨在简化这一过程,将这些核心功能整合到一个单一的、高性能的工具中,并通过单一配置即可管理。

Ruff 带来的主要优势:

  • 极速性能:由 Rust 编写,其检查速度比现有 Python 工具快一个数量级。这使得在大型代码库上运行检查变得轻而易举,不会拖慢开发流程。
  • 一体化解决方案:它能替代 Flake8 (及其众多插件)、isort、pydocstyle、mccabe、Pyflakes 等一系列工具。
  • 内置格式化器:从 0.0.260 版本开始,Ruff 集成了自己的格式化功能,旨在成为 Black 的替代品,同样强调非侵入性和确定性。
  • 高度可配置:虽然默认配置已经很合理,但Ruff提供了丰富的配置选项,允许用户根据项目需求启用/禁用特定规则、自定义规则行为等。
  • 易于集成:可轻松集成到 VS Code、PyCharm 等 IDE 以及各种 CI/CD 工作流中。

二、Ruff 的主要功能

Ruff 的功能主要包括代码检查 (Linting) 和代码格式化 (Formatting)。

2.1 代码检查 (Linting)

Ruff 可以检查代码的各种问题,包括但不限于:

  • 语法错误和潜在 bug:如未使用的变量、重复的导入、语法错误。
  • 代码风格问题:遵循 PEP 8 规范,如行长、缩进、空白行等。
  • 复杂性检查:例如函数或方法的圈复杂度 (通过集成 Pylint 的 C 规则)。
  • Docstring 检查:如缺少 docstring 或 docstring 格式不规范 (通过集成 pydocstyle 的 D 规则)。
  • 最佳实践检查:如使用 assert 而不是 raise、不必要的 else 块等。

Ruff 通过一系列规则 (rules) 来执行这些检查,每条规则都有一个唯一的代码 (例如 E501 代表行长超限)。它支持数百条规则,涵盖了 Flake8、isort、Pylint、Pyflakes 等工具中的常见检查。

Ruff 规则示例:

  • F401: 未使用的导入
  • E501: 行长超过最大限制
  • W292: 文件末尾没有新行
  • I001: 导入顺序不规范 (isort 风格)
  • D100: 缺少模块 docstring

2.2 代码格式化 (Formatting)

Ruff 的格式化器旨在提供与 Black 类似的非侵入式、确定性的格式化体验。它会根据一套固定的规则自动调整代码布局,目标是减少代码风格争议,让开发者专注于编写功能。

特点:

  • 确定性:给定相同的输入,总是产生相同的输出。
  • 非侵入性:只修改必要的格式,尽量不改变代码的抽象语法树。
  • 与 Linting 紧密结合:格式化通常也能修复一些格式相关的 Lint 错误。

三、安装与基本使用

3.1 安装

Ruff 可以通过 pip 安装:

1
pip install ruff

3.2 基本用法

假设你有一个名为 main.py 的 Python 文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
# main.py
import os, sys # F401


def hello_world(
name):
# This is a comment that is intentionally long to trigger E501 if line limit is 88.
message = f"Hello, {name}!"
print(message)


if __name__ == "__main__":
hello_world("Ruff User")

3.2.1 代码检查 (Linting)

运行 Ruff 进行代码检查:

1
ruff check main.py

你可能会得到类似这样的输出(取决于你的配置和 Ruff 版本):

1
2
3
4
5
main.py:2:12: F401 'sys' imported but unused
main.py:2:12: F401 'os' imported but unused
main.py:2:1: I001 One import per line
main.py:5:9: E501 Line too long (88 > 79)
Found 4 errors.

3.2.2 自动修复 (Auto-fix)

Ruff 能够自动修复许多检查到的问题:

1
ruff check --fix main.py

运行后,main.py 可能会变为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# main.py
import os # F401
import sys # F401


def hello_world(
name):
# This is a comment that is intentionally long to trigger E501 if line limit is 88.
message = f"Hello, {name}!"
print(message)


if __name__ == "__main__":
hello_world("Ruff User")

请注意,I001 (One import per line) 已经被修复,但 F401 (unused imports) 仍然存在,因为它们需要在后续的 fix 批次中处理或者需要用户手动确认。E501 通常不会被自动修复,因为它涉及到代码逻辑或风格的选择。

3.2.3 代码格式化 (Formatting)

从 Ruff 0.0.260+ 版本开始,你可以使用 format 命令进行格式化:

1
ruff format main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
# main.py
import os # F401
import sys # F401


def hello_world(name):
# This is a comment that is intentionally long to trigger E501 if line limit is 88.
message = f"Hello, {name}!"
print(message)


if __name__ == "__main__":
hello_world("Ruff User")

格式化器可能对空行、括号位置等进行调整。E501 在格式化中可能会尝试缓解,但如果行太长且无法合理拆分,它仍将是一个 lint 错误。

3.2.4 同时检查并格式化

Ruff 推荐在 CI/CD 中同时执行检查和格式化,以确保代码完全符合规范。

1
2
3
4
ruff check .
ruff format . --check # 在 CI/CD 中只检查是否需要格式化,不实际修改
# 或者
ruff format . # 在本地开发时直接格式化

四、配置 Ruff

Ruff 可以通过多种方式进行配置:

  • pyproject.toml (推荐):这是现代 Python 项目管理工具的标准配置文件。
  • ruff.toml
  • setup.cfg
  • flake8 的兼容配置(有限支持)

以下是一个 pyproject.toml 配置示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# pyproject.toml
[tool.ruff]
# 要启用或禁用的规则代码列表,或者规则组。
# 示例:启用所有默认规则 (`E`, `F`, `W`, `I`),并添加一些 `D` (pydocstyle) 和 `C` (复杂度) 规则。
# 使用 `ruff config` 命令查看所有可用的规则及其类别。
select = ["E", "F", "W", "I", "D", "C"]
ignore = ["E501"] # 忽略特定规则,例如忽略所有 E501 (行长超限) 错误
target-version = "py310" # 指定目标 Python 版本,Ruff 将根据此版本检查语法和特性。

# 允许自动修复的规则。如果未指定,所有选中的可修复规则都将进行修复。
# fixable = ["I001"]

# 不自动修复的规则。
# unfixable = []

extend-exclude = [
".git",
"__pycache__",
"venv",
"env",
"build",
"dist",
"*.pyc",
"*.egg-info",
".mypy_cache",
".pytest_cache",
]

# 针对特定文件或路径的配置。
[tool.ruff.per-file-ignores]
"__init__.py" = ["F401", "D"] # 针对 __init__.py 文件,忽略 F401 和所有 D (pydocstyle) 规则。
"tests/*.py" = ["D"] # 针对测试文件,忽略所有 D 规则。

[tool.ruff.pydocstyle]
# 配置 pydocstyle 相关的规则
convention = "google" # 例如,遵循 Google 风格的 docstring 规范

[tool.ruff.flake8-annotations]
# 配置 flake8-annotations 相关的规则
mypy-init-annotations = true

[tool.ruff.flake8-import-conventions]
# 配置 import-conventions
# 例如,允许 import pandas as pd 但禁止 import pandas as p
alias-modules = { "pandas" = "pd", "numpy" = "np" }

[tool.ruff.isort]
# isort 行为配置
known-first-party = ["my_package"] # 将 'my_package' 视为项目内部包
combine-as-imports = true # 合并如 `from foo import a, b` 为 `from foo import a; from foo import b`

[tool.ruff.format]
# 格式化器配置
docstring-code-format = true # 格式化 docstring 中的代码块
# line-length = 88 # 格式化器的行长,通常与 linting 的 E501 相关联

配置说明:

  • select:指定要启用的规则组或单个规则代码。你可以使用 ruff config 命令查看所有可用的规则及其所属类别。
  • ignore:指定要忽略的规则。
  • target-version:Ruff 会根据此版本检查语法和特性,以避免在旧版本 Python 中使用新语法或在旧版本中检查新特性。
  • exclude:指定要忽略的文件或目录。
  • per-file-ignores:针对特定文件或文件模式应用不同的忽略规则。
  • [tool.ruff.pydocstyle]、[tool.ruff.isort] 等:针对特定功能或插件进行更细粒度的配置。
  • [tool.ruff.format]:配置内置格式化器的行为,例如行长。

五、Ruff 在 CI/CD 中的应用

Ruff 的极速特性使其非常适合集成到持续集成 (CI) 和持续部署 (CD) 流程中。

典型的 CI/CD 流程:

在 CI 阶段,通常会执行以下命令:

  1. 检查 Lint 错误 (不自动修复):

    1
    ruff check .

    如果检测到任何错误,CI 将失败,并提示开发者修复。

  2. 检查格式化 (不自动修改):

    1
    ruff format . --check

    这将验证所有文件是否都已正确格式化。如果发现任何文件需要格式化,此命令将以非零退出代码退出,导致 CI 失败,强制开发者在提交前进行格式化。

通过这种方式,Ruff 能够在代码合并之前强制执行代码质量和风格规范,从而保持代码库的整洁和一致性。

六、Ruff 与传统工具的对比

特性 Ruff Flake8 (with plugins) + isort + Black
语言 Rust Python
速度 极速 (10-100x 快) 较慢
功能整合 Linting, Formatting, Import Sorting (一体化) 需多个独立工具配置和运行
配置 单一 pyproject.toml 或 ruff.toml 多个工具的独立配置
可扩展性 通过规则代码和自定义插件 (未来计划) 通过 Flake8 插件系统
安装 单一 pip install ruff 多个 pip install
内存占用 低 相对较高

七、总结与展望

Ruff 作为 Python 生态系统中的新星,以其卓越的性能和功能整合能力,正在迅速改变 Python 代码检查和格式化的格局。它不仅仅是一个替代品,更是一个强大的整合器,极大地简化了工具链,提升了开发效率。

对于任何重视代码质量和开发效率的 Python 项目,Ruff 都值得尝试和推广。随着其功能的不断完善和社区生态的成熟,Ruff 很有可能成为未来 Python 项目中不可或缺的基石工具。

未来展望:

  • 更完善的 IDE 集成
  • 更多定制化规则和插件支持
  • 持续优化格式化器,实现与 Black 的完全对等甚至超越。