2.1 规则的命名规范
Ruff 所有规则都有一个 "前缀字母 + 数字" 的短代码,例如 F401、E501、B007。这一命名直接沿袭自 Flake8 生态:
- 前缀字母(prefix)
- 表示该规则来自哪个"族"(rule family)——也就是对应原来 Flake8 的哪个插件。如
F= Pyflakes,E/W= pycodestyle,B= flake8-bugbear。 - 数字(code)
- 该族内该规则的编号,一般 3-4 位。编号在族内唯一,但不同族可能重复(如
E501和W501是两条不同规则)。
选择"整族"的写法也支持:--select F 会启用 F 族所有规则;--select F,E 启用 F 和 E 两族;--select E5 则只启用 E500-E599 之间的规则(前缀匹配)。
2.2 核心规则族一览
| 前缀 | 来源(原插件) | 典型用途 | 是否默认启用 |
|---|---|---|---|
F | Pyflakes | 真正的 Bug:未定义变量、未使用 import、未使用变量 | ✅ 默认 |
E/W | pycodestyle | PEP 8 风格:行过长、空白、缩进 | E 默认,W 部分 |
I | isort | import 排序与分组 | ❌ 需启用 |
N | pep8-naming | 命名规范:类名 CamelCase、函数 snake_case | ❌ 需启用 |
UP | pyupgrade | 升级过时语法:% → f-string、List → list | ❌ 需启用 |
B | flake8-bugbear | 易错反模式:可变默认参数、循环闭包 | ❌ 需启用 |
S | flake8-bandit | 安全:硬编码密码、eval、subprocess shell=True | ❌ 需启用 |
D | pydocstyle | docstring 规范:缺失、格式 | ❌ 需启用 |
C4 | flake8-comprehensions | 列表/字典推导式的优化建议 | ❌ 需启用 |
SIM | flake8-simplify | 简化代码:多余 if/else、冗余 not | ❌ 需启用 |
ANN | flake8-annotations | 类型注解完备性 | ❌ 需启用 |
RUF | Ruff 原创 | Ruff 自己新增的规则 | ✅ 部分 |
PERF | Perflint | 性能反模式 | ❌ 需启用 |
PL | pylint | Pylint 规则子集 | ❌ 需启用 |
不做任何配置直接跑 ruff check 时,Ruff 默认只开 Pyflakes 全族(F)和 pycodestyle 的一小部分(E4 import、E7 语句、E9 语法)。这保证"开箱即用"不会因风格问题刷屏。想开更多规则要在配置里写 select = [...]。
2.3 F 族:Pyflakes(找真 Bug)
F 族是最重要的族,绝大多数是货真价实的 Bug而不是风格问题:
# F401 — 未使用的 import
import json # 但是下面没用到 json
# F821 — 未定义的变量
print(undefined_name)
# F811 — 重复定义
def foo(): ...
def foo(): ... # 覆盖了上面那个
# F841 — 赋值后从未使用
def run():
result = compute()
return 0 # result 丢了
# F541 — f-string 没有占位符
msg = f"just text" # f 前缀多余
2.4 E / W 族:pycodestyle(PEP 8 风格)
E = Error(错误),W = Warning(警告)。常用规则:
- E501 line-too-long
- 行超过
line-length(默认 88)。 - E711 none-comparison
- 与 None 比较应用
is None而不是== None。 - E712 true-false-comparison
- 与 True/False 比较应用
is或直接真值判断。 - E722 bare-except
- 裸
except:会吞掉所有异常(包括 KeyboardInterrupt)。 - W291 trailing-whitespace
- 行尾多余空格。
- W605 invalid-escape-sequence
- 字符串里
"\d"这种不是合法转义的反斜杠——应改用 raw 字符串r"\d"。
2.5 I 族:isort(import 排序)
按 PEP 8 约定,import 要分三组:标准库 → 第三方库 → 本地模块,每组内字母序。Ruff 的 I 规则可自动整理:
# 修复前(I001 会报错)
import requests
import os
from .utils import helper
import json
# ruff check --select I --fix 后
import json
import os
import requests
from .utils import helper
2.6 UP 族:pyupgrade(升级过时语法)
Python 每代都会引入更好的写法,UP 族自动把老代码升级到现代语法:
# UP006 — 使用内置类型而非 typing.List
# 修复前
from typing import List, Dict
def f(xs: List[int]) -> Dict[str, int]: ...
# 修复后(Python 3.9+)
def f(xs: list[int]) -> dict[str, int]: ...
# UP007 — Optional[X] → X | None(Python 3.10+)
# UP008 — super() 代替 super(ClassName, self)
# UP031 — % 字符串格式化 → f-string
name = "world"
msg = "hello %s" % name # → f"hello {name}"
UP 族生效取决于 target-version(见第 3 章)。比如 UP007(Optional[X] → X | None)只有在目标 Python >= 3.10 时才触发,否则会改坏代码。
2.7 B 族:flake8-bugbear(易错反模式)
# B006 — 可变默认参数(Python 最著名的坑)
def bad(items=[]): # 所有调用共享同一个 list!
items.append(1)
return items
# B007 — 循环变量未在循环体中使用
for i in range(10): # 应改 for _ in range(10)
do_something()
# B023 — 循环变量被闭包捕获
funcs = [lambda: i for i in range(3)]
# funcs[0]() == funcs[1]() == funcs[2]() == 2,不是 0/1/2
2.8 用 ruff rule 查规则详情
$ ruff rule F401
# 展示该规则的含义、示例、是否可自动修复
$ ruff linter # 列出所有规则族
$ ruff rule --all # 列出所有规则(含详细说明)
在线版更直观:docs.astral.sh/ruff/rules——每条规则都有示例代码、Bad/Good 对比、可选配置项。
2.9 选规则的推荐起步集
刚从 Flake8 迁过来的项目,先别一次性开 800 条。建议从"无争议、修复量少"的族开始:
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"F", # Pyflakes(真 Bug)
"I", # isort
"B", # bugbear
"UP", # pyupgrade
"SIM", # simplify
]
跑通之后再考虑 N(命名)、C4(推导式)、RUF(Ruff 原创),以及 S(安全,后端项目尤其推荐)。
2.10 小结
- 规则编号 =
前缀字母族+数字,前缀决定"这条规则原本来自哪个插件"。 - F 族几乎都是真 Bug,永远开;E/W 是风格;I/UP/B/SIM 是高性价比;D/ANN/S 按项目需要开。
ruff rule CODE随时查一条规则干什么。- 默认只开 F + E4/E7/E9,其余须在
select中显式启用——下一章讲配置。