1.1 Ruff 是什么?
Ruff 是由 Astral 团队(即 uv 的作者)用 Rust 编写的一款 Python 静态代码质量工具。它同时扮演两种角色:
- Linter(代码检查器)
- 静态分析 Python 源代码,找出风格问题(如行太长)、潜在 Bug(如未定义变量)、反模式(如用可变默认参数)等,并给出建议。对应命令:
ruff check。 - Formatter(代码格式化器)
- 按统一规则重写代码的排版:缩进、引号、换行、参数对齐等。99% 兼容 Black。对应命令:
ruff format。
一句话概括:Ruff = Flake8 + Black + isort + pyupgrade + pydocstyle + bandit + ... 全部合在一个 Rust 二进制里,并且速度快 10-100 倍。
静态分析(Static Analysis)指"不运行代码,只看源码文本/AST"就能发现问题的技术。与之对应的是动态分析(运行时检查),如 pytest 测试覆盖率、运行时 profiler。Ruff、mypy、pylint 都属于静态分析。
1.2 与 Flake8 / Black / pylint 的对比
| 工具 | 语言 | 职责 | 速度(万行代码) | 当前定位 |
|---|---|---|---|---|
| Ruff | Rust | Lint + Format + 修复 | < 1 秒 | 新一代默认选择 |
| Flake8 | Python | Lint(含插件) | 20-60 秒 | 被 Ruff 替代中 |
| Black | Python | Format | 5-15 秒 | 被 ruff format 替代中 |
| isort | Python | 排 import | 3-10 秒 | 被 Ruff 规则 I 族替代 |
| pylint | Python | 深度 Lint + 类型推断 | 60-300 秒 | 仍有独特价值(类型推断) |
| mypy | Python | 类型检查 | 30-120 秒 | 与 Ruff 互补使用 |
Ruff 侧重"语法/风格/局部模式"的快速扫描,不做全局类型推断。若需要严格类型检查(例如 x: int = "abc" 的跨函数类型错误),仍要搭配 mypy 或 pyright。Astral 正在开发的 ty 项目(Rust 写的类型检查器)目标是未来替代 mypy。
1.3 为什么这么快?
Ruff 之所以快 10-100 倍,核心有三点:
- Rust 的零成本抽象 + 无 GC:AST 遍历、字符串处理、哈希表查询比 Python 原生快一个数量级。
- 并行文件处理:用
rayon多线程并行扫描所有 Python 文件,充分利用多核 CPU。 - 单次 AST 遍历执行所有规则:Flake8 每个插件都要各自遍历一次 AST;Ruff 把所有启用的规则在一次遍历中同时跑完。
AST(Abstract Syntax Tree,抽象语法树)是源代码被解析后形成的树状结构,每个节点对应一个语法成分(函数定义、变量赋值、表达式等)。静态分析工具不是直接扫"文本",而是扫 AST,这样才能区分"字符串 "def foo"" 和"真的函数定义 def foo()"。
1.4 安装 Ruff
Ruff 是单个静态链接的二进制,安装极简。按你已有的工具选择一种即可:
方式 A:uv 安装(推荐)
# 作为项目依赖
$ uv add --dev ruff
# 或全局工具(类似 pipx)
$ uv tool install ruff
# 免安装、一次性运行
$ uvx ruff check .
方式 B:pipx(全局隔离)
$ pipx install ruff
$ ruff --version
# ruff 0.11.x
方式 C:pip(项目 venv 内)
$ pip install ruff
方式 D:Homebrew(macOS)
$ brew install ruff
macOS/Linux 的系统 Python 是只读的。用 pipx 或 uv tool install 保证隔离。Windows 用户可直接 pip install ruff 到用户目录。
1.5 第一次运行:ruff check
新建一个 demo.py:
# demo.py
import os, sys # 多个 import 同一行
import json
def greet(name="world",):
msg = f"hello {name}"
print(msg)
return 0
unused = "never read" # 未使用变量
print(json.dumps({"a":1}))
运行:
$ ruff check demo.py
demo.py:2:1: E401 Multiple imports on one line
demo.py:2:8: F401 [*] `os` imported but unused
demo.py:2:12: F401 [*] `sys` imported but unused
demo.py:11:1: F841 [*] Local variable `unused` is assigned to but never used
Found 4 errors.
[*] 3 fixable with the `--fix` option.
每一行的含义:
- demo.py:2:1
- 文件路径:行号:列号,编辑器点击可直接跳转。
- E401 / F401 / F841
- 规则代码。字母是规则族(E=pycodestyle errors,F=Pyflakes),数字是该族下的具体规则。在第 2 章我们会完整介绍。
- [*]
- 表示该问题可以被
ruff check --fix自动修复。
1.6 第一次运行:ruff format
$ ruff format demo.py
# 1 file reformatted
执行后 demo.py 的排版会被重写:字符串统一成双引号、多余尾逗号去掉、语句间空行规范。Ruff format 默认与 Black 风格几乎一致,无需额外配置就能得到公认的美观排版。
在 CI 中通常只需要"检查格式是否正确,不实际写入文件",用 ruff format --check。若格式不一致返回非 0 退出码,让 CI 失败。
1.7 常用命令速查
$ ruff check . # 检查当前目录
$ ruff check --fix . # 检查并自动修复
$ ruff check --watch . # 文件变化时重新检查
$ ruff format . # 格式化
$ ruff format --check . # 仅检查是否需要格式化(CI 用)
$ ruff --version # 查看版本
$ ruff check --statistics . # 规则触发次数统计
$ ruff check --select E,F . # 只跑 E、F 规则族
1.8 小结与下一步
- Ruff 是 Rust 写的超快 Python Lint + Format 一体化工具,正在快速替代 Flake8/Black/isort。
- 安装:
uv tool install ruff/pipx install ruff,30 秒完成。 - 核心命令:
ruff check(找问题)+ruff format(调排版)。 - 输出里的
F401、E501都是"规则代码"——下一章系统讲解。
下一章我们将深入 Ruff 的规则体系:F/E/W/B/UP/I 这些前缀分别代表什么,为什么 Ruff 能复刻 Flake8 几十个插件。