ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Ruff规则集与规则码查询指南:用ruff list --select N快速掌握代码规范

Ruff规则集与规则码查询指南:用ruff list --select N快速掌握代码规范 1. 先搞清楚 ruff list --select N 到底在查什么Ruff 的--select参数平时做代码检查时用得最多用来告诉 linter“这次只跑哪些规则”。但很多人配置时只记住了常见的 E、F、N 这几个前缀等到想查某个规则集底下到底有多少条规则、每条规则具体叫什么名字时却不知道该敲什么命令。ruff list --select N就是在这种场景下很顺手的一个用法它把N当成规则集前缀去过滤命令会把该前缀下所有规则码和规则说明一次性列出来。这里的N不是某一条具体规则而是 pep8-naming 这个规则集的代号。官方把所有规则按照“前缀 数字编号”的方式排成一个大树大写字母前缀表示规则集或规则族数字部分表示具体某条规则。比如N801里的N代表命名检查族801代表其中的“类名应该使用 CapWords 风格”。所以ruff list --select N查出来的不是“某一条规则码”而是整个N前缀下的规则集合。想查别的规则集把前缀换成E、F、B、S等逻辑完全一样。为什么要专门用前缀去查因为 Ruff 的规则树是按语义分层的。直接看完整规则列表太吓人普通ruff check会输出一长串检查结果但很少会告诉你“这个前缀到底还包含哪些候选规则”。用--select配合前缀查询本质上是把规则树按分支切开来看适合做配置前调研、规则选型、以及排查为什么某个规则没生效。举个例子我在终端里跑ruff list --select N输出会类似这样节选N801 invalid-class-name N802 invalid-function-name N803 invalid-argument-name N804 invalid-first-argument-name-for-classmethod N805 invalid-first-argument-name-for-method N806 invalid-variable-in-function N807 dunder-function-name ...看到这个输出你就能知道N这个规则集里到底有哪些命名规范。这也是整个问题里“规则集/规则码有哪些”的第一层答案规则集就是前缀规则码就是前缀加数字编号一条一条列出来就是完整清单。1.1 命令格式与常用变体ruff list --select N里最核心的是--select参数。它不只在list这种查询命令里能用在真正执行ruff check时也是同一个参数。常见的几种写法ruff list --select N只查 N 前缀下的命名规则。ruff list --select E,F,N同时查多个前缀用英文逗号隔开。ruff list --select E5只查 E5xx 这部分规则比如 E501 这种行长度相关代码。ruff list --select ALL列出全部规则相当于把规则树整棵铺开。如果你用的 Ruff 版本比较新命令入口可能有变化用ruff rule --all也能达到类似的完整列表效果再用 grep 过滤前缀即可。本质上都是对规则树做前缀过滤思路完全一致。1.2 N 前缀到底管哪些规则N 是pep8-naming的缩写专门检查代码命名风格。它和 pycodestyle 的 E/W 不同E/W 更多关注空格、换行、缩进这种排版层面N 关注的是“名字取得合不合规”。比如函数名是不是小写开头、类名是不是 CapWords、方法第一个参数是不是self或cls、全局变量是不是全大写等。在实际项目里N 前缀很适合给二次开发团队用。因为命名规范是代码可读性的第一道关卡不需要太多智能判断规则本身也非常明确。开启 N 前缀后团队代码合进主干之前就能自动挡住一批不规范的命名比 code review 时由人肉去挑要省力得多。2. Ruff 规则集全览常见前缀速查表Ruff 最大的优势之一是把几十个 flake8 生态的插件规则集合并成了一个 linter。所以它支持的“规则集/规则码”不是一套而是很多套。下面这张表是我整理出来的常见前缀速查表覆盖了当前 Ruff 主版本里经常用到的大部分规则集。前缀就是规则集后面的数字才是具体规则码。前缀规则集来源主要关注点常见规则码举例Epycodestyle errors行长度、缩进、空白等风格错误E501、E111Wpycodestyle warnings编码风格警告如无效转义W605、W503FPyflakes未导入、未定义、未使用变量F401、F821Iisortimport 排序与格式I001Npep8-naming类名、函数名、参数名、变量名N801、N802、N805UPpyupgrade旧语法升级到新语法UP006、UP007Bflake8-bugbear容易出 bug 的写法B006、B008Aflake8-builtins变量覆盖内建名称A001、A002C4flake8-comprehensions列表推导式写法优化C400、C408C90mccabe圈复杂度C901Sflake8-bandit安全风险S101、S324SIMflake8-simplify简化代码写法SIM101、SIM108TIDflake8-tidy-importsimport 路径规范化TID251、TID252T10flake8-debugger调试代码残留T100、T101T20flake8-print调试用 print 残留T201、T203ANNflake8-annotations类型注解缺失ANN001、ANN201ARGflake8-unused-arguments未使用函数参数ARG001、ARG002ASYNCflake8-async异步代码质量ASYNC100、ASYNC109BLEflake8-blind-except过于宽泛的异常捕获BLE001COMflake8-commas尾随逗号规范COM812CPYflake8-copyright版权头声明CPY001Dpydocstyledocstring 规范D100、D103DJflake8-djangoDjango 模型与 ORM 细节DJ001、DJ003DTZflake8-datetimez时区不安全的 datetime 用法DTZ001、DTZ005EMflake8-errmsg异常消息格式EM101、EM102EXEflake8-executable文件可执行权限EXE001FAflake8-future-annotations未来注解语法FA100、FA102FLYflake8-flynt字符串格式化转 f-stringFLY002FURBrefurb代码简化重构建议FURB100、FURB116Gflake8-logging-formatlogging 格式化占位符G001、G004ICNflake8-import-conventionsimport 别名约定ICN001INPflake8-no-pep420普通包需包含init.pyINP001INTflake8-gettext国际化文本函数INT001ISCflake8-implicit-str-concat隐式字符串拼接ISC001、ISC003LOGflake8-logginglogging 使用细节LOG001、LOG002NPYNumPy 专用规则np 函数参数错误NPY001、NPY002PDpandas-vetpandas 用法问题PD002、PD003PERFflake8-perf性能相关写法PERF101、PERF203PGHpygrep-hooks用 pygrep 模式做钩子检查PGH001、PGH003PIEflake8-pie各种简化建议PIE790、PIE804PLC/PLE/PLR/PLWPylint约定/错误/重构/警告PLR0913、PLC2401PTflake8-pytest-stylepytest 测试风格PT001、PT006PTHflake8-use-pathlib用 pathlib 替代 os.pathPTH101、PTH118PYIflake8-pyipyi stub 文件规范PYI001、PYI006Qflake8-quotes引号风格Q001、Q003RETflake8-returnreturn 空值与 None 处理RET501、RET504RSEflake8-raiseraise 写法RSE102RUFRuff 专属规则综合建议RUF001、RUF100SLFflake8-self私有成员访问SLF001SLOTflake8-slotsslots使用SLOT000、SLOT101TCHflake8-type-checking类型检查专用 import 隔离TCH001、TCH002TDflake8-todosTODO 注释规范TD001、TD002TRYtryceratopstry/except 异常处理TRY001、TRY002YTTflake8-2020过期 datetime APIYTT101、YTT103这张表的重点不是让你背而是帮你建立“前缀就是规则集”的心智模型。看到F401知道是F前缀下的第 401 条规则看到B006知道是B前缀下的第 6 条规则。配置里select [F, B]就是一次性开启两个规则集。2.1 内置基础规则集E/W/F/I/N/UP这几个前缀是开箱即用最频繁的也是大部分人第一次用 Ruff 时最先接触的。E/W 来自 pycodestyle解决“排版风格对不对”的问题F 来自 Pyflakes解决“代码里有没被引用的导入、有没有未定义的名称”这种逻辑型问题I 来自 isort解决 import 块排序N 管命名UP 管语法现代化。其中我最常用的是F和UP。F401在提交 MR 前能帮我把无用的 import 全揪出来避免代码里堆积垃圾。UP007会把Optional[str]这类写法提示成str | None在 Python 3.10 项目里非常实用。不过要注意UP 这类规则属于“不断演进”的规则集Python 新版本一出它可能会新增一些规则码所以查规则的时候一定要先看当前版本的输出。2.2 第三方生态插件类B/S/SIM/TID/T10/T20 等Ruff 把 flake8 生态里的几十个插件合并了进来这才让它显得“大而全”。比如B是 flake8-bugbear专门抓可变默认参数def f(x[])这种坑S是 flake8-bandit专门做安全扫描会提示 assert 使用、SQL 拼接、不安全 hash 算法等风险SIM是 flake8-simplify会把if x: return True else: return False压成return x这类更简洁的写法。这些第三方规则集有一个共同特点它们不是官方 Python 规范而是社区经验的沉淀。开启它们之前最好先做一次“项目体检”不然可能满屏都是修改建议。我通常的做法是先用ruff list --select B看看 bugbear 有哪些规则再把里面明显冲突的项先 ignore最后跑一遍真实项目逐步收敛。2.3 Pylint 迁移规则集PLC/PLE/PLR/PLWPylint 是老牌 Python 静态检查工具规则数量多到让人头疼。Ruff 并没有完全复刻 Pylint 的每一条但把常见的几千条规则按类型分成了四个前缀PLC是 convention 约定类PLE是 error 错误类PLR是 refactor 重构类PLW是 warning 警告类。所有PL规则在rule说明里都会写明对应的 Pylint 原始编号方便老项目迁移时做对照。从老项目迁到 Ruff最常见的是原来 Pylint 配置里有load-plugins、disable...一大段迁到 Ruff 后直接写select [PL]并不能无脑继承因为PL家族规则太宽开启后会有一堆“建议”。我一般只开启其中几个子集比如PLR0913这种检测函数参数过多的规则它对接口设计挺有帮助。2.4 Ruff 专属规则集RUF 与实验性前缀RUF是 Ruff 自家的规则集不属于任何 flake8 插件。里面包括一些很实用的静态分析规则例如RUF100会检测代码里写了# noqa但其实没有对应告警的“僵尸 noqa”RUF001会检测容易混淆的 Unicode 字符类似把英文引号和中文引号混在一起的问题还有RUF010会提示在 f-string 里使用显式转换符号。除了RUFRuff 还在持续吸收新规则和实验性前缀。这些规则版本更迭比较快可能在某个版本里是RUF1xx下个版本就调整编号。所以我做项目配置时不太会把select [ALL]敞开用而是优先把稳定规则集加上等升级后跑一遍全量检查再决定新增哪些。3. 实操如何用查询命令、过滤规则与配置生效规则规则码查出来了接下来就要知道怎么把它用起来。很多人卡在“列出来是一回事让人真正生效是另一回事”所以这一部分我把查询、过滤、配置三个环节串起来讲。3.1 用查询命令快速找到目标规则最直接的用法是用--select的前缀过滤。比如我想看E前缀下有哪些行长度相关的规则不用翻文档直接查ruff list --select E5如果想精确查某一条规则用ruff rule直接输入规则码ruff rule F401这样能看到这条规则的完整说明、错误消息模板、以及推荐的修复方式。如果你想知道项目里当前到底启用了哪些规则可以结合配置文件和ruff rule --all一起用。把规则输出保存到文件里慢慢翻比在终端里滚动翻页舒服得多ruff rule --all rules.txt3.2 在配置文件里用 select 启用规则集Ruff 支持pyproject.toml和ruff.toml两种配置文件。常见写法是这样的[tool.ruff.lint] select [E, F, N, UP, B, S] ignore [E501, S101] [tool.ruff.lint.per-file-ignores] tests/** [S101, N802]这里最关键的一点是select的值既可以是前缀也可以是完整规则码。比如想只启用N801和N802两条规则可以直接写[N801, N802]。Ruff 会把前缀和具体规则码统一处理不会再额外展开整个N前缀这比 flake8 的select逻辑要灵活不少。但同样要注意ignore的优先级比select高。一条规则如果同时出现在select和ignore里最终结果是不生效。所以select [ALL], ignore [E501]这种搭配是可以的反过来select [E501], ignore [E501]就完全没意义纯粹是给自己挖坑。3.3 按文件类型或业务目录精确放行规则集全开之后最头疼的就是测试文件里一堆assert被S101报出来。这种情况不建议全局 ignoreS101因为测试代码里用 assert 是合理的但业务代码里出现 assert 就需要慎重。Ruff 提供per-file-ignores正是解决这个问题的[tool.ruff.lint.per-file-ignores] tests/** [S101, N802, N803] migrations/** [E501]这样业务代码仍然保持严格检查测试目录和迁移脚本这种特殊目录可以针对性放宽。我从实际使用经验里得到的建议是尽量把per-file-ignores写成目录通配符用tests/**而不是一个个文件名去写Ruff 对**的支持非常稳定后维护也更省心。3.4 版本差异与规则码更新Ruff 版本更新很快升级前最好先看看ruff rule --all的输出有没有变化。有些旧规则码可能在某个版本被重命名有些被合并进其他前缀。比如早期一些插件规则在 flake8 里有自己的编号迁移到 Ruff 后会改成不同前缀如果你照着网上老教程直接复制配置很可能出现“规则集不存在”的报错。我踩过最典型的坑就是直接抄别人发在博客上的select [T20]结果旧版本可能有效新版本已经把它改成T201或调整了前缀。所以遇到规则码失效先别急着找新规则替代第一时间跑ruff list --select 前缀看看当前版本到底认不认这个前缀。4. 常见问题与排查技巧实录规则码这种东西看起来只是字母和数字的拼写但实际操作中坑特别多。我把平时答疑时最常遇到的几个问题整理一下每一个都是真实项目里跑出来的经验。4.1 为什么 ruff list --select N 没有输出遇到过好几个人问这个问题。最常见的原因有两个第一Ruff 的规则前缀是大小写敏感的你写ruff list --select n它不一定能识别成 pep8-naming 的前缀。第二当前 Ruff 版本可能还没有启用该规则集。Ruff 会把新规则先放到 preview 状态默认不生效你直接查N可能只看到一部分需要加--preview参数才能看到完整列表。第三种情况比较隐蔽如果你的命令写成了ruff list --select N801这时查的就不是规则集而是单条规则。输出结果当然完全不一样。所以想查“整个规则集”一定要用大写前缀想查“某一条规则”才写完整规则码。4.2 规则码冲突同样是 PL怎么区分PL这个前缀非常特殊。它不是一个规则集而是 Pylint 规则的一个大类代码。你写ruff list --select PL得到的是全部 Pylint 相关规则但如果你在配置里只写[PL]它会把 PLC、PLE、PLR、PLW 全部启用范围大到无法收拾。建议按子前缀拆分处理PLC只查约定类PLR只查重构类。这样配置更可控排查问题时也能快速定位到具体是哪一类 Pylint 规则。4.3 select 和 ignore 的优先级到底谁更高这个问题的标准答案很明确在 Ruff 的规则选择流程里ignore的优先级高于select。也就是说一条规则只要进过ignore列表就算它同时被select选中了最终也不会生效。这里的“生效”是指不会出现在ruff check的检查结果里但规则本身仍然会被解析。正因为如此我特别不建议在select里写ALL然后又用ignore排除一堆规则。因为一旦以后想新增某个规则必须先查它有没有被ignore覆盖心智负担会很重。更推荐的做法是select只写你想要的规则集ignore只写“这个规则集里我不想用的少数几条”。这样配置文件和实际意图是一一对应的。4.4 升级 Ruff 后规则码忽然失效Ruff 每个版本都可能新增规则码也可能调整已有规则码的所属前缀。比如早期版本里某个规则在T前缀下后面因为分类更清晰被移到了RUF前缀下。升级后旧配置就会报“unknown rule”或者更糟的是直接静默忽略掉导致你以为规则还在检查实际根本没启用。我的建议是升级前先生成一份当前版本的规则清单和旧版本做 diff。Ruff 官方变更日志也会写明破坏性变更但更直接的办法是用ruff rule --all对比一下。如果项目里规则配置特别多可以先用 CI 跑一次ruff check看到异常输出再逐条排查比升级后手动试每条规则要快得多。4.5 如何快速找出项目里真正生效的规则别靠猜直接用命令验证。最简单的方法是故意写一行明显违规的代码然后跑ruff check --select 规则码看它报不报。如果报了说明这条规则生效如果不报说明被某种配置排除了。更全面一点可以这样查ruff check . --select ALL --statistics它会按规则统计项目里各类告警的数量这样你一眼就能看出项目里实际触发了哪些规则哪些规则开到但目前没触发过。把这些统计结果留存过一段时间再跑一次就能看到规则库的覆盖效果。5. 我在实际使用中的三个习惯最后分享几个我个人用下来的习惯比较主观但都是踩过坑换来的。第一不要迷信ALL。把所有规则集全开确实很爽但代价是大量告警噪音。一旦出现几百个RUF或PL提示团队很快会对 linter 失去信任。我更倾向于按“代码质量阶梯”来开先开 E/W/F 保证基础再开 N 规范命名最后按项目需要加 B/S/UP。每个阶段跑一遍确认没有明显冲突再往下一层。第二用ruff list --select 前缀做规则选型时一定要带上“为什么开它”这个判断。比如B006能抓默认可变参数这种规则几乎无脑开C90圈复杂度规则就要小心它可能和团队的分层设计思路冲突。规则码不是越多越好而是越贴合项目越好。第三配置完规则集之后把ruff check接到 pre-commit 或 CI 里而不是只依赖编辑器实时报错。因为编辑器里看到的告警是临时的很容易被手动关闭CI 里跑出来的结果才是全项目统一的。规则码这个东西查询一次解决的是“有没有”的问题真正难的是“开哪些、放哪些”这需要每个项目根据自己的代码现状和团队偏好来定。先把前缀和规则码的关系理清楚配置 Ruff 就不难了。
返回列表