- 静态分析
- 代码质量
- Lint
- 开发工具
【免费下载链接】pylint
It's not just a linter that annoys you!
本文以 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):
- 仅关注
func为属性访问(Attribute)且属性名为format的调用; - 通过
utils.safe_infer推断format调用对象的类型; - 若推断结果不可知(
UninferableBase),直接跳过,避免误报; - 若推断为无值(空),则进一步匹配
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 后建议关注以下几点:
- 消息级别变化:
try-except-raise从 E0705 变为 W0706,若 CI 以错误级别阈值(如--fail-on=E)运行,需调整预期; - 新检查器:
misplaced-format-function为错误级别,升级后可能在新代码中发现此类笔误,可先用--disable=misplaced-format-function临时关闭或逐步修复; - 误报修复:长名称函数不再触发
invalid-name,useless-return对单语句 return 不再误报,带__getattr__的模块豁免no-member,CI 中的“历史误报豁免清单”可以相应清理; - 新选项:文档字符串检查可通过
--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!
相关推荐
Pylint 3.3 版本深度解析:新检查项、版本兼容策略与误报修复全景
Pylint 3.3 版本深度解析:新检查项、版本兼容策略与误报修复全景 Pylint 3.3 是 2024 年 9 月 20 日发布的次版本,随后以补丁形式持
静态分析代码质量Lint开发工具Pylint 2.1 系列版本解析:2.0 首发后的修复浪潮与新检查器
Pylint 2.1 系列版本解析:2.0 首发后的修复浪潮与新检查器 导读 :Pylint 2.1 与 2.1.1 是 2.0 大版本发布后的首批小版本,定位
静态分析代码质量Lint开发工具Pylint 2.4 版本深度解析:14 个新检查器与关键行为变更实战指南
Pylint 2.4 版本深度解析:14 个新检查器与关键行为变更实战指南 本文以 Pylint 官方 2.4 版本发布说明( doc/whatsnew/2/2
静态分析代码质量Lint开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考