☰
Ruff规则筛选实战:用好--select命令快速定位所需检查规则
2026/10/6 3:46:19 网站建设 项目流程

打算在项目里把Ruff的规则好好筛一遍的人,应该都遇到过那个困惑:ruff list命令把六百多条规则一次性铺开,光看都看不过来,更别说怎么从中挑出自己想要的。我也是在调一个老项目的检查策略时,整天和ruff list --select N这个组合命令打交道,折腾了几天才把筛选逻辑彻底弄明白。我把自己的实操过程整理成文,希望能帮你省掉踩坑的时间。这篇文章会从规则代码的结构讲起,逐步拆解--select N的匹配逻辑,再用几个真实场景演示完整筛选流程,最后一并列出我实际遇到过的坑。

Ruff是Python社区里目前相当主流的静态检查工具,底层用Rust实现,跑得飞快,而且内置了几百条规则,覆盖代码风格、错误隐患、导入规范、命名规范、安全检测等方向。但规则多反而是把双刃剑:不做筛选就把所有规则打开,项目里会瞬间充满噪音,真正重要的错误反而被淹没。所以“筛选规则”本身,就是一个值得花时间研究的正规操作。

1. 规则筛选前必须搞懂的事:规则代码长什么样

1.1ruff list输出的三列信息

ruff list命令的作用非常直接:把你当前安装的Ruff支持的所有规则一口气列出来。输出默认是文本表格,每一行一条规则,核心是三列:规则代码、规则名、所属大类。大致感觉是这个样子:

E501 line-too-long pycodestyle-errors F401 unused-import pyflakes ...

第一条E501就是大家很熟悉的行长度检查规则,line-too-long是这个规则的人类可读名称,pycodestyle-errors表示这条规则源自pycodestyle的error类。这三列信息其实已经告诉你筛选的时候该怎么下手了:你既能看到代码前缀,又能看到含义,还能知道它归属哪个检查体系。

第一次执行ruff list的时候不要慌,你看到的不是整个列表有什么问题,而是Ruff把“规则菜单”完整端到了你面前。六百多条规则虽然多,但它们不是平铺的,而是按前缀进行了天然分组。你在终端里可以配合less逐页翻看,也可以直接接管道用grep按关键词筛选,比如想确认所有和“unused”(未使用)相关的规则,执行ruff list | grep -i unused就够了。

1.2 规则代码的字母前缀就是“筛选抓手”

Ruff的每条规则都有一个唯一代码,形式是“字母前缀+数字编号”,比如E501、F401、B006。字母前缀代表这套规则的来源或主题领域,数字编号是具体规则的序号。这里的字母前缀就是--select N筛选的核心抓手。

我整理了一份实用前缀对照表,都是日常最常用的几类:

前缀来源或方向示例规则简单说明
Epycodestyle - errorE501行长度、空白、空行等格式错误类
Wpycodestyle - warningW605格式边界情况的警告类
FPyflakesF401未使用导入、未定义名称等逻辑问题
Bflake8-bugbearB006bug隐患,比如可变对象做函数默认参数
Iisort分类I001import导入排序规范
Npep8-namingN801命名规范,比如类名、函数名大小写
Sflake8-banditS101安全相关,比如检测assert用于除调试外的场景
Cmccabe 复杂度C901函数复杂度过高检测
UPpyupgradeUP032老语法升级建议,比如提示改f-string

看到这个表你会发现一个规律:--select E意味着把pycodestyle的error类规则全选上,--select F就是把Pyflakes的规则全选上,--select N自然就是命名规范的整套规则。这也是--select N里那个N在日常使用中最常见的含义——它表示你要筛选的规则前缀,比如“我想筛选命名相关的N系列规则”。

1.3 为什么不能一把梭全开

有些刚上手Ruff的人会觉得,规则全开不是最保险吗?实际体验过就知道完全不是那么回事。规则一全开,几百条提示里面有大量的风格偏好类警告,这些警告不一定是错误。比如某种内置函数被覆盖了、某个命名风格建议改一下,这些建议可能是合理的,但在某个具体项目里噪声大于价值。

我自己维护的老项目里就有个经典案例:用到了大量动态生成类名的元编程代码,如果打开整组N系列命名规则,几百个类名报错,但代码本身在业务上下文里完全成立。这时候需要的不是“规则全开”,而是“先把N系列整体看一遍,再决定开哪几条、放哪几条”。筛选规则不是逃避检查,而是让检查更贴合你的项目现状。

2.--select N的匹配逻辑:这个N不是数字那么简单

2.1 四种写法对应四种粒度

--select N这个参数看起来简洁,实际能接受的值有四种不同粒度:

  • 完整规则代码:--select F401,只启用未使用导入检查这一条规则,粒度最细。
  • 两位前缀:--select E5,启用所有以E5开头的规则,一类规则里的一个子分组。
  • 单字母前缀:--select E,启用整个pycodestyle error类,粒度最粗。
  • 多个值组合:--select E,F,I,把几个不同前缀的规则集合并启用,这是日常用得最多的写法。

注意,--select后面跟的N并不是一个数字编号,而是一套“规则代码匹配模式”。Ruff拿到你的参数后,会按规则代码前缀去匹配,看哪些规则的代码以这个前缀开头。这个设计思路和flake8一脉相承,但Ruff实现得更干净。比如你写--select F4,实际匹配的就是F401、F403、F405这类以F4开头的规则,而不是“第4个F规则”。

2.2 精确匹配和前缀匹配的边界

有件事值得专门说一下:即使你可以用--select E把整个E系列打开,Ruff真正启用规则时还会考虑规则的具体前缀是否在“允许列表”里。简单理解就是,ruff list --select E是“列出E系列全部规则”,而ruff check --select E .是“检查时启用E系列全部规则”,两者在“筛选”这个动作上是一致的,区别只在“看”和“用”。

在命令行上,ruff list --select E501会精确列出一条规则,加一个--select E则会列出所有E开头的规则。你可以先通过list界面反复试探,确认某种写法能筛出什么结果,再放心地组合到你最终需要的select配置里。这种“先list后check”的思路,是筛选规则最稳的路径。

2.3 select和ignore是怎么互相配合的

Ruff里还有另一个参数叫--ignore,和--select是天生的一对。--select决定“从规则库里选哪些”,--ignore决定“已经选中的集合里再剔掉哪些”。优先级顺序是先选出集合,再从集合里排除。

举个例子,我想启用B系列全部bug隐患检查,但项目里有一个旧的公共函数大量使用了可变默认参数,这条B006一时半会改不完,那我就可以写--select B --ignore B006。这条命令先选中B系列全部规则,然后明确忽略B006这一条,既保持了对该隐患的感知能力,又给了存量代码改造的缓冲期。

这个组合逻辑在list命令里同样生效:ruff list --select B --ignore B006列出的结果里就没有B006了。我经常用这个命令在改动配置前先“预演”一遍,确认最终生效的规则集合长什么样,避免直接改动配置后发现和预期不符。

2.4 配置文件里对应的写法

--select N的命令行参数,写进配置文件时就是静态配置里的select列表。以最常见的pyproject.toml为例,配置长这样:

[tool.ruff.lint] select = ["E", "F", "B", "I", "N"] ignore = ["B006"]

注意新版Ruff把lint相关配置放在[tool.ruff.lint]下面,而不是老的[tool.ruff],这是因为Ruff后来加入了formatter功能,需要把lint和format两组配置区分开。如果你把select直接写在[tool.ruff]下,新版Ruff会提示配置位置不对,虽然还能运行,但格式上已经算过时了。

命令行参数和配置文件之间是覆盖关系:命令行临时指定的select优先级更高,会覆盖配置文件里的select。这一点在排查问题的时候特别重要,见后文。

3. 实操过程:从需求到命令的完整筛选流程

3.1 四步法:从规则库到最终配置

我在实际操作中总结出了一个四步法,用来应对“想启用某种检查但不知道规则代码是什么”的情况:

  1. 先用ruff list --select 某个前缀或ruff list | grep 关键词定位候选规则。
  2. 用list的输出确认规则代码和含义,挑出真正需要的规则。
  3. 在命令行用ruff check --select 候选规则 .临时验证效果,看会不会和项目现状冲突。
  4. 确认无误后把代码写进pyproject.toml的select列表,形成持久配置。

这套流程的核心思想是“先看菜单,再点菜,最后下单”。Ruff的命令行工具非常灵活,给了充分的试错空间,完全没必要一上来就动配置文件。

3.2 场景一:只想筛选导入相关的规则

假设团队最近在规范import导入组织方式,想让导入排序、未使用的导入都检查起来。第一步先用前缀筛选查看I系列规则:

ruff list --select I

执行之后,终端会列出所有I开头的规则,主要就是isort导入排序相关的那几条。如果你想顺带看看F系列里和“未使用”相关的导入规则,可以继续筛选:

ruff list --select F4

这里的F4是F系列里一个子分组,覆盖未使用导入、import * 这类问题。两步操作下来,导入规范相关的候选规则基本都在眼前了。

3.3 场景二:单独把命名规范筛选出来

命名检查是Ruff里最需要谨慎启用的一类,因为不同项目的命名习惯差异很大。有的团队坚持函数名全小写下划线,有的团队部分地方允许驼峰。先把N系列全部列出来看一遍:

ruff list --select N

这会列出从类名、函数名、变量名到常量名等一整套命名规范规则。你可能会在里面看到N801这种类名规则,也可能看到N802这类函数名规则。这时候逐条判断团队到底需要哪几条,而不是盲目地把整个N系列导入配置。

实操中我的做法是:先把N系列全看一遍,然后用ignore把不适用的部分剔掉,而不是逐条往select里加。因为命名规则往往“整体是一套逻辑”,局部排除比局部挑选更符合语义。

3.4 场景三:由报错信息反查规则代码

还有一种更常见的情况:你在IDE或者CI日志里看到Ruff报了一个提示,觉得这个检查很合理,想把同类规则都打开,但不知道它的规则代码。这时候直接用关键词反查。

比如日志里提示“Do not use mutable data structures for argument defaults”,想确认这是哪条规则,执行:

ruff list --select B | grep -i mutable

很快就能定位到B006,对应规则名mutable-argument-default。确认之后,如果你觉得这类bug隐患检查有用,再把整个B系列过一遍,挑几张合适的放进配置。反查过程比翻文档高效得多,因为Ruff规则名本身就是很好的关键词。

3.5 场景四:多类别组合筛选并验证

当你最终确定了几个大方向,比如格式、逻辑、导入、命名、bug隐患,可以一次性组合筛选:

ruff list --select E,F,I,B,N

这个命令的输出就是将来你可能要启用的完整规则集合预览。看到结果没问题后,下一步临时验证:

ruff check --select E,F,I,B,N .

注意这里用的是ruff check,后面跟了一个.,表示对当前目录做实际检查。你会立刻看到这个“规则大礼包”在真实代码上的表现,哪些文件报了哪些问题一目了然。

验证通过后,把同样的select写进配置文件,然后去掉命令行参数,日常执行ruff check .就会自动按配置筛选规则了。

3.6 场景五:在默认规则基础上临时追加

这里有个特别容易踩的坑:Ruff在没有配置select时,默认只启用一部分规则,大致是E4、E7、E9和F系列中的部分内容。当你第一次在命令行执行--select E,F,I,B,N时,这个选择会覆盖默认规则,而不是追加。也就是说,你等于把默认的E4、E7、E9都丢了,换成了完整的E系列,检查结果会突然变得“严格很多”。

如果你只是想临时在默认基础上追加一组命名规则,正确写法应该是把默认的前缀也写进去:

ruff check --select E4,E7,E9,F,N .

这种做法在排查问题时很实用,因为你不想因为少写了默认规则而误判“新规则导致一堆新报错”。理解这个覆盖语义之后,你再看配置文件里的select,就会明白那是一个“完整清单”,不是“追加清单”。

4. 常见问题与排查实录

4.1 把N理解成数字或漏掉大小写

“--select N”里那个N,最大的误区就是理解成某一个数字编号。我第一次看这个命令时也觉得奇怪,为什么select后面跟个数字?实际这个N是规则前缀,或者说是一个“匹配模式”。如果你执行--select 5,Ruff会直接提示找不到匹配规则,因为规则代码不可能以数字开头。

另一个高频小问题是大小写。Ruff的规则代码前缀是大写字母,比如F401,小写f401不会被识别。虽然ruff list输出的列表里全部是大写,但手敲命令时下意识打成小写的情况并不少见。遇到 “no rules matched” 之类的提示,先检查大小写。

4.2 搞混 list 和 check 的职责

我见过有人把ruff list --select E501当成“检查代码里有没有E501问题”来用,执行完发现只是打印了一条规则信息,没有检查结果,觉得命令坏了。其实这两个命令分工完全不同:

命令职责典型用法
ruff list --select N查看/筛选规则库信息ruff list --select I
ruff check --select N按N规则实际检查代码ruff check --select I .

list是“菜单”,check是“上菜后试吃”。筛选规则的完整工作流是:在list里确认规则,到check里验证效果,最后写入配置。分不清这两步,会让整个过程混乱不少。

4.3 select覆盖导致“规则突然变少”

配置好select之后,如果你在命令行再执行一次--select,Ruff会用命令行参数覆盖配置里的select。这样会导致一个现象:本地排查时选了一组临时规则,排查完忘了关,第二天跑ruff check发现结果和CI完全不一样。CI没有命令行参数,用的是配置文件里的select;本地带参数,覆盖了配置。

排查这类问题的方法很简单:执行ruff check --show-settings .,Ruff会打印出实际生效的配置,包括select和ignore。先看这里,再对照命令行参数,基本一查一个准。

4.4 规则代码不存在时的报错处理

如果select里写了一个不存在的规则代码,Ruff会有清晰的报错信息,指出 “rule ...” 不存在。常见原因有两个:一是拼写错误,比如把I001写成I002;二是想用的规则属于需要开启preview功能的“预览规则”。Ruff的规则有稳定和非稳定之分,部分新规则需要加--preview参数或配置preview = true才生效。遇到这种情况,先执行ruff list | grep 关键词确认规则代码是否真实存在,再检查这条规则是否标注了preview标志。

4.5 高效筛选规则的小工具组合

如果六百多条规则还是太多,我通常会组合一些小工具提高筛选效率:

  • ruff list | less,分页浏览全部规则,适合第一次看规则库时建立整体认知。
  • ruff list | grep -i "import",按关键词过滤规则名,快速定位主题相关规则。
  • ruff list --select E,按前缀过滤,适合已知分类后的精确浏览。
  • ruff list --select B --ignore B006,先选后排除,预演最终生效的规则集合。

这一套组合下来,再大的规则库也能在几分钟内完成一轮筛选。我自己的做法是先把规则库整个看过一遍,然后把常用前缀记下来,之后几天之内就能把整个项目的Ruff规则配置稳定下来。

5. 最后说点实际操作中的体会

Ruff的设计哲学在“规则筛选”这件事上体现得很彻底:它先把所有规则透明地摊开,再给你一个足够灵活的参数去组合、预览、排除。ruff list --select N这个命令只是入口,真正核心的是前缀匹配逻辑和“先查看、再验证、后持久化”的工作方法。我自己最终给老项目定的配置是E、F、I、B、N五类为主,再配合少量S系列安全规则,代码质量检查在CI里跑得很稳定,开发过程中的噪音也明显减少。如果你现在正对着六百多条规则发愁,我的建议是不要一上来就想着全开或全关,先花十分钟把ruff list --select的几个用法各试一遍,你的项目需要什么规则、不需要什么规则,很快就会有答案了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询