ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Ruff规则码全解读:从ruff list到N系列命名规范

2026/10/8 3:10:16 拓冰建站 浏览量
Ruff规则码全解读:从ruff list到N系列命名规范 1. 为什么你需要一张“规则码地图”1.1 规则码前缀可不是随便起的第一次看到ruff list --select N这个命令我估计很多人都懵了一下这个 N 到底是指任意规则码还是真有 N 开头的规则答案是两者都占了。N 既是命令行参数里常见的“占位符”也是 Ruff 规则体系里真实存在的一个前缀家族继承自 flake8-pep8-naming 插件。如果不把这事掰扯清楚后面配置select时你八成会在 E、F、W、N、UP、SIM 这些字母里迷失方向。Ruff 的规则码设计上完全沿用了 flake8 生态的命名习惯一个英文字母前缀加一串数字比如E501、F401、N802。前缀代表规则来源或所属类别数字是该类别下的具体编号。这套体系的妙处在于它能让你光看编码就知道规则在管什么看到 E 就想到 pycodestyle 的格式问题看到 F 就想到 Pyflakes 的未使用导入、未定义名称这类逻辑问题看到 N 就想到命名规范。用惯了之后你扫一眼报错就能判断要不要修、怎么修不用像某些老式 linter 那样还得把鼠标悬停在波浪线上看解释。而ruff list --select N这个命令本质上就是一张“规则地图”的查询入口。它会列出所有以 N 开头的规则码以及对应的简要说明让你在打开编辑器、开始写代码之前先知道自己选中的规则集到底包含哪些检查项。这个习惯非常重要——很多团队配置select [N]全凭感觉结果上线后发现 N 规则把你项目里一票老代码的类名、函数名、参数名全给标红了这才回头去查自己到底开了什么。与其事后手忙脚乱不如先花三分钟把家底摸清楚。1.2ruff list命令要解决什么问题Ruff 作为目前 Python 生态里速度最快的 linter 和 formatter一个问题就是规则数量实在太多了。我从 0.1 版本用到 0.9 版本亲眼看着它把 flake8 及其几十个常用插件的规则全部内置规则码从几十个一路涨到八百多个。这时候传统的ruff check --help或去看文档就有点不够用了你需要一个能在终端里快速检索、筛选、导出规则清单的命令。ruff list干的就是这件事。在我看来这个命令最实用的场景有三个。第一个场景是配置前调研你想给项目加上命名规范但不知道具体有哪些可选项直接ruff list --select N一眼看全。第二个场景是排查冲突两条规则看起来矛盾比如某个写法同时命中了 UP035 和 ICN001你想知道它们各自属于哪个集合用--select分别过滤就能快速定位。第三个场景是写文档或给团队做培训把规则清单导出成文本贴到 Wiki 里比让队友自己去翻官网省事多了。还需要注意版本差异。Ruff 的命令行工具一直在迭代早期版本我常用的是ruff linter来列规则后来又改成了ruff rule加ruff list的组合。如果你执行ruff list发现命令不存在大概率是版本有点老建议直接升级到 0.9 或更新的版本。旧版本临时用ruff linter顶上问题也不大只是输出格式和过滤参数可能略有不同。1.3 版本差异与命令家族速览这里我顺手把 Ruff 目前常用的几个“查看类”命令列一下帮你搭个整体认知框架。ruff list负责列出规则清单支持--select按规则码/前缀过滤ruff rule负责查看某一条规则的具体说明、示例和修复方式ruff check是实际执行检查的命令也可以带--select临时指定规则集。这三兄弟配合起来基本覆盖了从“看地图”到“查详情”再到“执行检查”的完整链路。有一个细节值得单独拎出来说ruff list --select N里的 N 不只接受前缀也可以接收单个规则码比如ruff list --select N802。它还能接受逗号分隔的多个条件比如ruff list --select N,UP会把命名规范和 pyupgrade 这两类规则一起列出。我在实际使用中更喜欢先把可能涉及的几个前缀一起拉出来对比比如ruff list --select E,F,N,UP这样能明显感觉到它们之间的边界和重叠比单独看某一个更有利于全局决策。2. 规则集/规则码全家族盘点主流前缀一览2.1 继承自 Flake8 生态的“老牌前缀”Ruff 做得最聪明的一件事就是把 flake8 及其插件生态的规则全部兼容过来让老玩家无缝迁移。这一批老牌前缀是规则体系的地基也是你配置select时最常用的几个。先说E系列。它对应 pycodestyle 的 errors主要管代码格式问题比如E501行太长、E302函数之间需要空行、E711不要用 None而要用is None。大部分 E 规则都能自动修复格式化能力跟 Black 目标一致后很多 E 规则在你使用ruff format后就不会再触发了因为它们已经被格式化器处理掉了。你可以把 E 系列看成是对代码“长相”的基本要求。W系列是 pycodestyle 的 warnings典型的如W605说的是字符串里出现了无效的转义序列。这一系列平时触发不多但如果要做严格的代码规范建议还是开着因为它能提前帮你发现一些字符串里的隐患。F系列来自 Pyflakes是逻辑层面的硬伤检测未使用的导入F401、导入但未使用导致的重定义F402、通配导入F403、未定义名称F821、未使用的局部变量F841、f-string 里根本没有占位符F541等。F 系列我建议任何项目都无条件开启它抓的都是会实际影响代码运行质量的问题误报率极低。再往下是C系列和I系列。C 系列里最出名的就是C901对应 mccabe 的圈复杂度检测函数复杂到一定阈值就会报警是代码重构的强推手。I 系列对应 isort负责导入排序规则典型如I001导入未排序或未分组。Ruff 自带了 isort 的全部功能并支持通过配置项自定义排序规则。最后就是N系列了这个我在第三大节会重点拆解因为它虽然只是命名规范却是团队协作中吵架最多的地方。2.2 从插件转正的一大批“现代前缀”如果说 E/F/W 是老一辈的 check那下面这批前缀就是 flake8 生态里那些优质第三方插件的“转正版”。Ruff 团队把它们内置进来之后我们终于不用再为了几个检查项去单独 pip install 一票插件了。UP对应 pyupgrade作用是让你的代码用上更新的 Python 语法。比如UP007会提示你把Optional[int]写成int | NonePython 3.10UP035会提醒你更换废弃的导入路径。这个系列我建议跟着项目的 Python 版本走版本够新就全开。B系列来自 flake8-bugbear专门抓“代码里可能存在的 bug”比如B006警告你用可变对象做函数默认参数B008警告你在默认参数里调用了函数。这两个规则在面试题里经常出现开了 B 系列之后这类问题一眼就能被揪出来。SIM系列来自 flake8-simplify目标是让代码更简洁。比如SIM105会建议你用contextlib.suppress(...)代替一大段try...except: passSIM108会建议你把简单的if/else缩写成三元表达式。S系列来自 flake8-bandit是安全检测S101警告你使用了 assert 做安全检查S301警告你反序列化量的不可信数据。对于有安全要求的项目S 系列能起到一定的提前拦截作用但要注意它有少量误报。A系列是 flake8-builtins管的是变量名覆盖内置函数的问题比如你定义一个变量叫listA001 就会报警。ARG系列是 flake8-unused-arguments会检查函数参数是否未使用ARG001表示函数中未使用的参数。PTH系列是 flake8-use-pathlib它像一个“传教士”不断提醒你os.path.join换成Path.joinpath、os.path.exists换成Path.exists()。我刚开始觉得这系列管得宽后来用熟了pathlib之后真香了。2.3 框架专属与类型标注相关的前缀如果你在写 Django、Pandas 或者写很多类型标注下面这些前缀你早晚会遇到。DJ系列对应 Django 的检查项比如DJ001会提醒你别在TextField上使用nullTrueDJ003会提醒你把IntegerField的blankTrue改成nullTrue。这类规则对 Django 项目非常友好能省去不少追查数据库字段定义的时间。PD系列对应 pandas-vet是专门给 Pandas 代码用的检查比如PD002告诉你直接调用DataFrame.可用的方法而不要走属性访问。虽然我感觉这系列对大部分数据分析脚本来说有点过于严格但如果是维护公共库的话还是建议开着。ANN系列是让 Python 社区又爱又恨的规则集它强制你给函数参数和返回值写类型注解。ANN001提示参数缺少类型注解ANN201提示公开函数缺少返回类型注解ANN401则会警告你使用了Any作为类型需要显式关闭或配置白名单。TCH系列来自 flake8-type-checking管的是“仅用于类型检查的导入”应该放在TYPE_CHECKING块里从而避免运行时无谓导入导致的循环依赖问题。PYI系列则是专门针对.pyi存根文件的规则集。另外PT系列是 flake8-pytest-style管的是 pytest 写法的规范比如PT001建议用pytest.fixture()而不是pytest.fixture。D系列就是 docstring 的规范检查了它体量庞大从D100到D417覆盖了文档字符串的存在性、格式、参数说明完整性等内容。这个系列要谨慎开因为老代码里几乎不可能有完整的 docstring一旦开了就会面临海量报错需要配合ignore或者分阶段推进。2.4 Ruff 自研规则与性能、安全系列最后这部分属于“Ruff 自家特色”也是其他 linter 不一定有的东西。RUF系列是 Ruff 自己开发的规则专门解决别的工具管不到的场景。最有代表性的就是RUF100它会报告“无用的 noqa 注释”——你写了# noqa但那一行根本没有触发任何规则注释就是多余的。还有RUF001/RUF002会检测到字符串/注释里混入了容易混淆的 Unicode 字符RUF005会提醒你在拼接集合时改用可解包方式。我在多个项目里都犯过“加了一堆 noqa 之后不知道删”的毛病RUF100 简直是强迫症的救星开着它就能让 noqa 保持干净。PERF系列是性能相关的检查典型如PERF401会让你把循环里逐个 append 的操作改成生成器或推导式。这一系列对追求性能的库作者很有价值但对业务系统来说属于锦上添花我一般会选择性开启。FBT系列是 flake8-boolean-trap专门警告布尔参数带来的代码可读性隐患比如FBT001会提示“函数里的布尔参数不好建议改成明确的关键字常量”。PLC/PLE/PLW系列则是来自 pylint 的规则分类分别代表约定、错误和警告如果你之前用过 pylint 会比较熟悉但注意它的规则码前缀是三位字母组合在--select里要精确匹配。我还想提一下ERA系列来自 eradicate 插件ERA001会检测出注释掉的代码并提醒删除。对维护脏乱老项目的来说这个规则一开就能把死代码清个大半。Q系列管的是引号风格T系列管的是调试代码残留TD系列管的是 TODO 和 FIXME 注释的规范性。这些前缀虽然小众但每个都有它的用武之地。Ruff 规则体系几乎覆盖了你在写 Python 时能想到的所有检查维度这既是好事也是负担——选择太多容易选择困难症所以配置前一定要先用ruff list摸一遍家底。3. 聚焦 N 规则集命名规范那点事3.1 N 规则集到底在管什么说回标题里那个看起来有点神秘的 N。N 前缀在 flake8 生态里对应的是pep8-naming插件简单说就是“命名规范检查器”。它不管你的代码逻辑对不对、格式好不好看它只管一件事名字起得符不符合 PEP 8 的约定。类名是不是该用 CapWords函数名是不是该用小写下划线方法的第一个参数该叫self还是cls常量是不是该全大写。在团队协作里命名不遵守约定最大的后果就是代码阅读成本高你永远在猜这个变量是干嘛的、这个函数是不是会被当作别的东西用。Ruff 内置的 N 规则集覆盖了 PEP 8 中几乎所有命名约定场景。我的经验是新项目从第一天起就该把这个规则集打开成本极低收益却能一直持续。老项目则需要谨慎——历史代码里广泛存在的mixedCase变量名、非Error结尾的异常类会让 N 规则集一开就出现成百上千条告警。这不是坏事它等于给了你一份“命名债清单”关键是你要决定是硬着头皮分批次还债还是暂时忽略一部分规则再逐步收紧。3.2 N801 到 N818 逐个拆解下面我把 N 规则集里比较常见的几个规则拉出来说说这些都是我在实际项目里反复见过的类型。N801说的是类名应该使用 CapWords 约定也就是大写开头的驼峰命名比如class UserService而不是class user_service。Python 内置类也都是大写开头这条规则全项目通用建议直接开着。N802是函数名应该使用小写加下划线比如def get_user()而不是def getUser()。这套约定几乎适用于所有 Python 代码没什么好犹豫的。N803管的是参数名应该小写def func(UserName):这种写法会被标红。这个规则在从 Java/Go 转 Python 的团队里特别常见刚换语言的人很容易把 Java 的驼峰参数习惯带进来。N804针对 classmethod 的第一个参数要求命名为clsN805针对实例方法的第一个参数要求命名为self。这两个规则能在你写元类、装饰器、类工具方法时及时提醒你把约定写对避免“self 叫做 this”这种让人难受的写法。N806是函数内部变量也应该小写。这里的边界需要解释一下它只管局部变量不管全局变量和常量。我在写算法题或数据处理脚本时经常随手写res []、tmp {}这个其实符合规则但如果你写Res []就会被 N806 拦下来。N811管的是常量命名应该全大写加下划线比如MAX_RETRY 3。N818则是要求自定义异常类的名字以Error结尾比如class ConfigError(Exception)而不是class ConfigException(Exception)。至于N807、N812、N813、N815、N816、N817这些规则它们在命名规范里属于更细枝末节的场景比如导入名的规范、全局作用域里混合大小写变量的治理等。坦白讲我在实际项目里遇到这些规则的频率非常低偶尔看到官方案例才知道原来是这么回事。如果你用ruff list --select N把它们列出来会发现定义都还比较清晰只是因为大多数人的代码风格已经比较统一所以很少触发罢了。这条经验也说明了为什么配置前先列一遍规则非常重要你不会有意识地去想你需不需要一条你没见过的规则只有先让它出现在你面前你才知道原来还有这种检查维度。3.3 N 规则集的启停策略与典型误报N 规则集并不是开得越全越好它的误报和“适合性”问题都很明显。我见过最典型的场景是为了配合测试框架团队把一个工具类写成全小写风格N801 立刻报警。你当然可以加 noqa但更好的做法是先判断这个类是不是真的要按普通类处理。如果它是一个对外暴露的辅助函数集合不如直接把它改成函数模块或者显式配置区间忽略。另一个容易误伤的典型场景是科学计算和数据分析代码。很多来自 MATLAB 或 R 的变量习惯比如X_train、y_test这种半标准写法会被 N816 或 N815 标出来。这时候不要硬改因为它们可能对应着外部数据集的字段名改了反而降低可读性。我的建议是在这类代码文件上用 per-file-ignores 按目录豁免比如数据探索 notebook 的目录直接忽略 N 规则而不是在全局硬关。团队的规则不是用来折磨人的它应该是服务代码可读性的。4. 实操从命令到配置的一站式用法4.1 三分钟用ruff list --select N生成规则清单实操环节先上硬菜。你的环境只要装好了 Ruff版本建议 0.9 以上直接在终端执行ruff list --select N我本地的输出大概长这样不同版本措辞会略有差异但结构类似N801 (naming-class) Class names should use the CapWords convention N802 (naming-function) Function names should be lowercase N803 (naming-argument) Argument names should be lowercase N804 (naming-classmethod) First argument of a classmethod should be named cls N805 (naming-method) First argument of an instance method should be named self N806 (naming-variable) Variable names should be lowercase N807 ... N811 (naming-constant) Constant names should be all uppercase N812 ... N813 ... N815 ... N816 ... N817 ... N818 (naming-exception) Exception class names should use the Error suffix可以看到每条规则的输出都由三部分组成规则码、规则短名、一句话说明。短名非常有用它比数字编号更贴近语义比如naming-method一看就知道跟实例方法有关。如果你想把结果存下来发给同事可以加个输出重定向ruff list --select N naming_rules.txt再把这份清单整理进你的项目规范文档比在会议上口头讲半小时效率高得多。我也建议你顺手执行一下ruff list --select E,F,I,UP这组命令把它们各自的输出对照着看一遍你会发现不同规则集之间的视角差异非常明显——E 在乎格式F 在乎逻辑I 在乎导入顺序UP 在乎语法现代化。理解了这种差异“该选什么”这个问题就迎刃而解了。4.2 用ruff rule深挖单条规则的完整档案ruff list只告诉你规则存在而ruff rule则能告诉你这条规则到底怎么用、为什么存在。比如你想知道 N802 具体会在什么情况下报警执行ruff rule N802输出会包含规则的完整描述、触发场景的示例代码、修复后的正确代码有时还会给出“这条规则要不要关掉”的讨论背景。这个命令是我在做团队宣讲时必用的工具——与其我费口舌解释什么是 CapWords 命名不如直接在终端里把官方的解释和示例投影到屏幕上大家的理解速度会快很多。还有一个小技巧当你看到一个报错码不确定它属于哪个前缀、自己有没有开启这个规则集时可以用ruff rule查看它的分类信息。比如我遇到过C901的告警但我的 select 列表里没有写 C实际上它是因为我用了ALL选择器才被带出来的。通过ruff rule C901快速确认来源后就能决定是把它保留、忽略还是在 per-file-ignores 里单独豁免。4.3 在 pyproject.toml 中落地 select 配置命令行里的--select只是临时生效真正的配置要写进项目的配置文件里。Ruff 支持pyproject.toml、ruff.toml和.ruff.toml三种配置入口我更推荐写在pyproject.toml里这样整个项目的工具配置都能集中到一处。一个典型的配置如下[tool.ruff.lint] # 启用规则集E 格式错误、F Pyflakes、N 命名规范、I 导入顺序、UP 语法现代化 select [E, F, N, I, UP, B] # 命名规范里 N806 先关掉等老代码清理完再开 ignore [N806] [tool.ruff.lint.per-file-ignores] # 测试文件里允许 assert tests/** [S101]注意这里有个坑select配置的是“最终启用的规则集”它和命令行下的--select行为一致都是取并集关系。也就是说select [E, N]和select [E]加select [N]效果完全一样不存在后来覆盖前面的问题。如果你想在某个目录或文件上排除某些规则就按我上面的写法在per-file-ignores里单独管理。还有一个升级版玩法是extend-select它用于在已有基础配置上追加规则适合团队统一基础规范、个别项目再自行扩展的场景。我自己维护的一个基础配置模板是这样的[tool.ruff.lint] # 基础集合 select [E, F, I, N, UP] # 项目专属扩展 extend-select [B, SIM, RUF]这样既能保证基础规范的一致性又能给项目留出定制空间。Ruff 的配置项互相组合非常灵活我建议是在团队里固定一套“黄金配置”不要每个人都去调否则规则失控是迟早的事。4.4 组合选择器的常见套路最后说说我在不同项目里的选型套路供你参考。第一类是快速原型和脚本项目我通常只开E,F,I,UP它们能保证代码基本健康和可维护又不至于在前期开发时被大量规范问题恶心到。第二类是长期维护的库或核心服务我会扩大到E,F,I,N,UP,B,SIM,RUF,PERF这时代码质量已经完全交给机器把关。第三类是安全敏感项目在第二类基础上追加S,C再按实际情况豁免误报。组合选择器时有一个非常实用的参数--preview。Ruff 会把一些新规则标记为 preview 状态如果你用--select ALL或想体验新规则记得加上这个参数比如ruff check --select ALL --preview .就用这套命令我能在几秒钟内扫完一个中型项目的所有检查项。不过说实话ALL这种全开模式在日常开发中不太推荐因为很多规则会互相重叠甚至冲突报错噪音会变得很大。全开模式更适合临时性的全面体检日常开发保持一个稳定的规则子集才是正解。5. 常见问题与排查技巧实录5.1 规则码不存在或命令报错怎么办如果你执行ruff list --select XXX时报错说“找不到规则”九成是两种情况。第一种是规则码拼写不对比如把N802写成了N8020或者把TCH003写成了TCH3。第二种是版本太老新版本才有的规则在你的旧版本里还不存在。我的处理方式是先跑一遍ruff list不带任何参数看看当前版本到底有哪些规则可用再结合ruff rule确认写法。如果你用的是很旧的 Ruff 版本ruff list这个命令本身可能就不存在。这时候我建议优先升级到最新稳定版因为 Ruff 的迭代速度非常快旧版本不仅可能缺少新规则还可能在格式化行为上有细微差异影响团队一致性。升级之后拿一个中等规模的项目跑一遍重点看有没有规则码在升级后被归入更高的“稳定性等级”导致原先的 ignore 配置失效。5.2 规则冲突与 noqa 标记的正确姿势规则冲突在 Ruff 里并不少见最经典的就是命名规则 N 系列里某条导入相关规则可能和 I 系列的导入排序规则在“要不要改名”上产生不同意见。遇到这种情况先判断哪条规则更贴近你的项目语境然后在ignore里把不那么重要的那条排除掉。千万不要为了绕过检查随手加# noqa因为 RUF100 会反过来检查这些 noqa 是不是真的有用。如果需要用 noqa格式是这样写的def getUser(): # noqa: N802 ...它同时指定了规则码可读性更好也能防止你把其他规则误伤。我建议团队统一规定noqa 必须带规则码不带规则码的一律视为无效这样 review 代码时一眼就能看出原因。如果你发现自己经常要加某个规则的 noqa那说明这条规则和项目风格不合拍应该去配置文件里把它 ignore 掉而不是让代码到处充斥着豁免标记。5.3 从零搭建一套团队的规则组合我给不少团队做过 Ruff 落地这里分享一个还算靠谱的推进路线。第一步先把E,F,I,UP开起来跑一次全项目检查把报错数量落在文档里作为基线。第二步新增N,B,SIM,RUF同样跑一次评估工作量和代码风格冲击。第三步如果团队愿意接受更严格的类型标注再把ANN系列加上同时约定ignore掉ANN401和某些过细的规则。每一步之间的间隔最好留出 1-2 个迭代周期让成员们消化新的规则避免一上来就“血洗代码库”。这期间有个特别值得做的事把ruff list的输出和团队的编码规范文档对照起来凡是文档里没有覆盖的规则要么补上说明要么关掉。很多团队的“规则文档”和“实际配置”是脱节的文档写的是“变量命名要清晰”配置里却开着 N802/N803两人吵架时谁也不服谁。让配置跟着文档走或者让文档跟着配置走总之要统一。5.4 持续维护规则配置的几个习惯规则配置不是一次设完就能一劳永逸的。Ruff 每隔一段时间就会加入新规则原来的 preview 规则可能转正已经废弃的规则可能被移除。我自己的习惯是每个季度跑一次ruff list --select ALL --preview看看多了什么新东西然后挑有价值的规则加进配置。这个习惯花了不了多少时间但能让项目的代码风格始终跟得上语言社区的最新讨论。还有一个小技巧用ruff check . --statistics看看当前项目里各类规则触发的频率排名。如果某个规则长期处于“零触发”状态那它对你项目就是无用的可以关掉降低噪音反过来某个规则触发频率异常高说明团队在这类问题上普遍有改进空间值得专门开会对齐一次写法。规则配置的本质是一个动态博弈的结果它反映的是当前团队对代码质量的真实要求和认知水平。我个人在折腾这些规则码的过程中最大的体会是规则本身并不难懂难的是在整个项目里找到适合你的那一组。用ruff list把清单看清楚用ruff rule把每个规则搞明白再用一两周时间观察它在真实代码里的表现最后才把它写进配置——这套流程走下来你收获的不只是一份能跑通的配置还有一套对代码风格的判断标准。以后再去新项目照着这套方法重新推导一遍几分钟就能定出合理的规则组合。