☰
Pylint 2.1 版本发布深度解析:新检查器、误报修复与行为变更全景
2026/10/13 1:43:15 网站建设 项目流程
  • 静态分析
  • 代码质量
  • Lint
  • 开发工具

【免费下载链接】pylint

It's not just a linter that annoys you!

项目地址:https://gitcode.com/gh_mirrors/pyl/pylint
点击查看免费下载

本文以 Pylint 官方 2.1 版本发布摘要(doc/whatsnew/2/2.1/summary.rst)为骨架,结合仓库源码与功能测试用例,系统梳理该版本引入的新检查器misplaced-format-function、检查级别的调整、一系列误报与崩溃修复,以及新增的--default-docstring-type命令行选项。读者读完可完整掌握 Pylint 2.1 的行为变化细节,并能对照当前仓库源码理解每条变更背后的实现原理。

版本概览与定位

Pylint 2.1 于 2018-08-01 发布,随后的 2.1.1 补丁版于 2018-08-07 发布。按官方发布摘要的描述,本版本的主要内容是修复 2.0 发布后暴露的各种 bug,同时带来少量新功能:

  • 新增一个检查器misplaced-format-function(格式化函数误用检查);
  • 对既有检查try-except-raise的严重级别进行调整(错误 → 警告);
  • 适配 Python 3.7 的abc模块结构变化与模块级__getattr__新特性;
  • 移除invalid-name对函数/属性名称长度的 30 字符上限;
  • 修复若干误报(false positive)与崩溃问题;
  • 新增--default-docstring-type命令行选项。

以下逐项展开,每条变更均可在当前仓库源码或测试中找到对应实现。

新检查器:misplaced-format-function(E0119)

这是 Pylint 2.1 引入的唯一全新检查器,其核心目标是捕捉在非字符串对象上调用.format()的写法。最常见的原因是右括号位置放错,例如:

print('value: {}').format(123) # bad —— format 作用在 print(...) 的返回值(None)上 print('value: {}'.format(123)) # good —— format 作用在字符串字面量上

第一行中,print(...)返回None,紧接着在None上调.format(),最终代码会抛出AttributeError;第二行才是正确的字符串格式化写法。该检查器正是为了提前发现这类几乎必然是笔误的代码。

消息定义

在当前仓库中,消息定义位于 pylint/checkers/base/basic_checker.py,ID 为E0119:

"E0119": ( "format function is not called on str", "misplaced-format-function", "Emitted when format function is not called on str object. " 'e.g doing print("value: {}").format(123) instead of ' 'print("value: {}".format(123)). This might not be what the user ' "intended to do.", ),

它属于错误(Error)级别(E 前缀),其 symbol 为misplaced-format-function,可用--disable=misplaced-format-function关闭。

实现原理

检查逻辑由_check_misplaced_format_function实现(basic_checker.py),并在visit_call中被调用(basic_checker.py):

  1. 仅关注func为属性访问(Attribute)且属性名为format的调用;
  2. 通过utils.safe_infer推断format调用对象的类型;
  3. 若推断结果不可知(UninferableBase),直接跳过,避免误报;
  4. 若推断为无值(空),则进一步匹配call_node.func.expr是否为print(...)调用——即“在print()返回值上调用.format()”这一典型误用场景,命中即上报misplaced-format-function。

这种“先保守推断、再对 print 场景兜底”的双层设计,体现了 Pylint 在静态推断不确定时追求“宁可不报、不误报”的取向。

功能测试佐证

仓库中配套的功能测试位于 tests/functional/m/misplaced_format_function.py,覆盖了正反两方面的用例:

print('value: {}').format(123) # [misplaced-format-function] print("value: {}").format(123) # [misplaced-format-function] print('value: {}'.format(123)) # 正确写法,不报 print('{} Come Forth!'.format('Lazarus')) # 正确写法,不报

同时测试了类方法与实例方法的场景(测试文件):

def format_string(self): self.string.format() self.get_string().format() print(self.get_string()).format() # [misplaced-format-function] print(self.get_string().format()) obj = FakeClass('Voila!!!') print(obj.get_string()).format() # [misplaced-format-function]

预期输出文件 tests/functional/m/misplaced_format_function.txt 记录了 4 处应上报的位置,与测试文件中的# [misplaced-format-function]标注一一对应。

2.1.1 中的修复

2.1.1 补丁版修复了该检查器的一个崩溃问题:当format作用于类属性且无法正确推断时,Pylint 会崩溃(对应 issue #2384)。修复后,检查器对类属性场景也能稳定工作——这正是_check_misplaced_format_function中safe_infer失败即返回的设计由来。

检查级别调整:try-except-raise 从错误降级为警告

在 2.1 之前,try-except-raise(在except处理器中立即raise的冗余写法)属于错误级别(E0705);2.1 起将其降级为警告级别(W0706),对应 issue #2323。

当前仓库中的消息定义位于 pylint/checkers/exceptions.py:

"W0706": ( "The except handler raises immediately", "try-except-raise", "Used when an except handler uses raise as its first or only " "operator. This is useless because it raises back the exception " "immediately. Remove the raise operator or the entire " "try-except-raise block!", ),

降级背后的语义考量是:虽然except: raise是冗余代码(可以删除raise或整个 try-except 块),但它并不构成逻辑错误,因此从“必须修复的错误”调整为“建议改进的警告”,降低了对既有代码库的门槛。触发逻辑见 exceptions.py:仅当except处理器中没有捕获特定异常时(裸raise且无具体异常类型)才上报。

适配 Python 3.7:abc 模块与模块级getattr

2.1 的两项变更都源于 Python 3.7 的语法/标准库变化。

正确处理 abc 模块的 Python 实现名称

Python 3.7 中,abc模块同时存在 C 实现与 Python 实现,但 Python 实现的文件名与 Pylint 此前预期的不同,导致部分检查在推断abc相关类型时出现混乱(对应 pylint-dev/astroid#2288)。2.1 起正确识别abc模块的 Python 实现新名称,使基于abc.ABCMeta、抽象方法等的检查恢复正常。

带getattr的模块默认豁免 no-member

Python 3.7 为模块(Module)引入了__getattr__支持(此前只有类可以定义)。当模块通过__getattr__动态提供成员时,静态分析无法可靠判断某个成员是否存在。2.1 起,Pylint 对这类模块默认豁免no-member检查——与类上已有的处理方式保持一致:既然无法确定,就采取安全做法,跳过对该模块的成员检查(对应 issue #2331)。

当前仓库中no-member检查的豁免逻辑集中在 pylint/checkers/typecheck.py,文档注释明确列出了多种跳过场景,包括:

  • owner 是函数且带有装饰器;
  • owner 是实例且实现了__getattr__/__getattribute__;
  • 模块被显式忽略;
  • 访问节点被except AttributeError/Exception/bare except保护;
  • 枚举类例外:虽然枚举通过元类暴露动态__getattr__,但成员访问时并不触发它,因此枚举仍需检查(typecheck.py)。

invalid-name:移除 30 字符长度上限

2.1 修复了一个长期存在的误报:此前invalid-name会对超过 30 字符的函数名与属性名触发“名称无效”告警,但名称长度并不等于命名风格违规。2.1 起该长度上限被完全移除(对应 issue #2047),长名称的函数、方法、属性不再因长度因素被误报为invalid-name。

这也符合命名风格检查的设计初衷:invalid-name关注的是命名风格(如 snake_case、camelCase 与正则的匹配),而非名称长度。

误报与崩溃修复集锦

2.1 集中修复了一批 2.0 遗留的误报与崩溃问题,以下按变更点逐一说明。

undefined-variable:lambda 中自引用类名

修复了 lambda 表达式中引用尚未绑定完成的自引用类名时产生的undefined-variable误报(对应 issue #704)。例如在类定义过程中,lambda 内引用类自身的名称,此时名称尚未完全定义,但 Pylint 不应误报未定义变量。

no-else-return:明确导致问题的分支类型

no-else-return(R1705)此前只提示“else多余”,2.1 起消息会明确指定是哪一个分支(if/elif/try/except)触发了多余 else(对应 issue #2295)。消息定义见 pylint/checkers/refactoring/refactoring_checker.py,其模板为:

'Unnecessary "%s" after "return", %s'

两个占位符分别填入分支类型信息,帮助开发者快速定位多余 else 的确切位置。

bad-continuation:文件第一行行为不一致

修复了bad-continuation(续行缩进问题)在文件第一行上的不一致行为(对应 issue #2281),使第一行的续行缩进检查与其余行保持一致。

全局禁用选项无法作用于最后一行

修复了一个 bug:通过全局disable选项(命令行或配置文件)禁用某些消息时,文件最后一行上的该消息仍会被发出(对应 issue #2278)。修复后,全局禁用对最后一行的消息同样生效。

useless-return:单个 return 语句不再误报

useless-return(R1711)用于提示“函数末尾的孤立return/return None可安全删除”。2.1 前的版本中,若函数体只有一行且这一行就是return本身,也会被误报为 useless;2.1 起不再上报(对应 issue #2300)。

官方给出的理由非常明确:

当函数预期返回一个可选值时,我们仍然希望显式写出return;虽然pass也能达到同样效果,但不够显式,函数可能看起来像缺失了实现。

当前实现位于 refactoring_checker.py:_check_return_at_the_end首先要求函数体内恰好只有一个return 语句(多于一个时走_check_consistent_returns流程),随后:

last = node.body[-1] if isinstance(last, nodes.Return) and len(node.body) == 1: return # 单语句且该语句就是 return,直接豁免

即:当return是函数体唯一的语句时,直接跳过检查;否则若最后一个语句是裸return或return None,才上报useless-return。

next() 参数无法推断时的崩溃

修复了 Pylint 在无法推断next()的参数值时直接崩溃的问题(对应 issue #2316)。修复后,推断失败场景会安全降级处理而非抛出异常中断分析。

not-an-iterable:异步迭代器

not-an-iterable用于提示“对不可迭代对象进行了迭代”。2.1 起,对异步迭代器(async iterator)不再发出该消息(对应 issue #2311);但如果用普通迭代协议去迭代异步迭代器,仍然会正常上报——因为那确实是错误的用法。

新选项:--default-docstring-type

这是 2.1 引入的另一个实质性新功能:当 Pylint 的文档字符串检查无法自动猜测docstring 风格时,通过--default-docstring-type指定一个默认类型(对应 issue #1169)。

该选项定义于文档字符串检查扩展 pylint/extensions/docparams.py:

( "default-docstring-type", { "type": "choice", "default": "default", "metavar": "<docstring type>", "choices": list(utils.DOCSTRING_TYPES), "help": "If the docstring type cannot be guessed " "the specified docstring type will be used.", }, ),
  • 类型:choice(枚举选择);
  • 默认值:default;
  • 可选值:由DOCSTRING_TYPES字典(pylint/extensions/_check_docs_utils.py)定义,包含五种:
DOCSTRING_TYPES = { "sphinx": SphinxDocstring, "epytext": EpytextDocstring, "google": GoogleDocstring, "numpy": NumpyDocstring, "default": Docstring, }

即sphinx、epytext、google、numpy与default。

在实现中,该配置被传入utils.docstringify(...)(docparams.py),用于解析函数/方法的文档字符串,进而检查参数文档、返回文档、yield 文档等是否齐全。这对混合使用多种 docstring 风格的代码库非常实用:当自动猜测失败时,显式指定类型可避免检查器因“猜错风格”而产生误报。

其他 2.1 变更补充(来自完整变更日志)

除发布摘要外,doc/whatsnew/2/2.1/full.rst 还记录了以下补充变更:

  • trailing-comma-tuple现在同样对yield语句发出(对应 issue #2363);
  • redefined-argument-from-local只获取当前作用域函数的参数(对应 issue #2364),避免跨作用域误报;
  • chain.from_iterable对 dict 的 values/keys 迭代时,不再发出dict-*-not-iterating误报;
  • 2.1.1:当内建函数在try-except内部使用时,不再对 Python 3 内建检查发出*-builtin(对应 issue #2228);
  • 2.1.1:simplifiable-if-statement在处理下标(subscript)访问时不再误报。

版本升级与验证建议

对于仍停留在 2.0 的用户,升级到 2.1 后建议关注以下几点:

  1. 消息级别变化:try-except-raise从 E0705 变为 W0706,若 CI 以错误级别阈值(如--fail-on=E)运行,需调整预期;
  2. 新检查器:misplaced-format-function为错误级别,升级后可能在新代码中发现此类笔误,可先用--disable=misplaced-format-function临时关闭或逐步修复;
  3. 误报修复:长名称函数不再触发invalid-name,useless-return对单语句 return 不再误报,带__getattr__的模块豁免no-member,CI 中的“历史误报豁免清单”可以相应清理;
  4. 新选项:文档字符串检查可通过--default-docstring-type=google等方式显式指定默认风格。

要验证当前环境行为,可直接对测试样例运行 Pylint,例如:

# 验证 misplaced-format-function pylint tests/functional/m/misplaced_format_function.py # 指定默认 docstring 类型 pylint --default-docstring-type=google your_module.py

小结

Pylint 2.1 是典型的“修复驱动”版本:以消除 2.0 引入的误报和崩溃为主要目标,同时谨慎地加入了一个新检查器(misplaced-format-function)和一个新配置项(--default-docstring-type),并对 Python 3.7 新特性(模块级__getattr__、abc双实现)做了适配。这些变更在当前仓库中均有清晰的源码实现(basic_checker.py、exceptions.py、refactoring_checker.py、typecheck.py)与配套的功能测试(tests/functional/m/misplaced_format_function.py)可供进一步研读,也体现了 Pylint 在“减少误报、增强稳健性”方向上的一贯演进路线。

  • 静态分析
  • 代码质量
  • Lint
  • 开发工具

【免费下载链接】pylint

It's not just a linter that annoys you!

项目地址:https://gitcode.com/gh_mirrors/pyl/pylint
点击查看免费下载

相关推荐

上一篇:fastRAG 开源项目教程
下一篇:终极硬件优化游戏数据库:打造完美ROM包的完整指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

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

立即咨询