【问题标题】:how to configure pylint for greater accuracy如何配置 pylint 以获得更高的准确性
【发布时间】:2020-06-26 09:54:32
【问题描述】:

从 pylint 得到误报

考虑这段代码:

previous = None
for word in ['you', 'cannot', 'be', 'serious']:
    if previous is not None:
        print(previous[0], word)
    previous = word

这是输出(这里没有惊喜):

$ python3 test.py
y cannot
c be
b serious

使用pylint 检查它会得到以下结果:

$ pylint3 test.py
No config file found, using default configuration
************* Module test
C:  1, 0: Missing module docstring (missing-docstring)
C:  1, 0: Constant name "previous" doesn't conform to UPPER_CASE naming style (invalid-name)
E:  4,14: Value 'previous' is unsubscriptable (unsubscriptable-object)

--------------------------------------------------------------------
Your code has been rated at -4.00/10 (previous run: -4.00/10, +0.00)

如您所见,pylint 抱怨表达式 previous[0] 基于 previous 初始化为 None 的事实,即使当它具有该值时无法访问该语句。此外,尽管在最后一行进行了赋值,但它仍以 previous 是一个常量为基础抱怨命名风格。

问题:是否有任何合适的 pylint 配置可以避免此类误报,而不会引入同样明显的误报,如果有,为什么这不是默认配置?

尝试的解决方案:禁用测试(导致假阴性)

例如,我可以完全抑制unsubscriptable-object 警告,方法是创建一个包含pylint3 --generate-rcfile 输出的$HOME/.pylintrc,并对其进行编辑以将unsubscriptable-object 添加到禁用测试列表中(参见@987654336 @在[MESSAGES CONTROL]部分中)。

但是,如果我简单地以这种方式禁用测试,然后验证以下代码:

"false negative"  # silence docstring warning (fair enough)

print(None[0])  # this line will fail

它告诉我:

$ pylint3 test2.py
Using config file /home/<myuser>/.pylintrc

--------------------------------------------------------------------
Your code has been rated at 10.00/10 (previous run: 10.00/10, +0.00)

所以仅仅禁用测试并不是真正的答案。

版本和平台信息

版本信息:

$ pylint3 --version
Using config file /home/<myuser>/.pylintrc
pylint3 1.8.3, 
astroid 1.6.0
Python 3.6.9 (default, Apr 18 2020, 01:56:04) 
[GCC 8.4.0]

平台:Ubuntu 18.04.4 LTS

【问题讨论】:

  • 您使用的是最新版本的 pylint 吗?根据我的经验,新版本不会出现不可订阅对象错误误报。似乎他们定期改进他们的类型干扰逻辑。无效名称错误不是恕我直言误报。您在配置文件中为全局变量选择 UPPER_CASE_NAMING 样式,“previous”实际上是一个全局变量。所以 pylint 正在做它应该做的事情。您始终可以使用 #pylint disable=xxx 来抑制单行中的 xxx 错误。
  • @PaulCornelius 尝试使用 2.5.3(最新版本)并且基本相同。关于大写,错误消息指的是“常量”。它不是一个常数。
  • 潜在相关:pylint issue #3328,以及issues labeled topic-control-flow。我认为类型提示会有所帮助,但似乎并非如此。

标签: python pylint pylintrc


【解决方案1】:

Pylint 是一个静态类型检查器,具有该类型实用程序的所有限制。它不会读懂你的想法,它只会读懂你的代码。它的目的是告诉你看起来可疑的代码,有时你不得不告诉它忽略某些事情,因为你真的想这样编写程序。

如果您希望 Pylint 成为一个完美无瑕的代码纳粹,它可以识别您的每一个错误,永远不会忘乎所以,永远不会错过任何事情,您会失望的。如果你认为它是一个友好的观察者,可以在你运行程序之前发现你的一些错误,那么它是非常强大的。我认为它是必不可少的工具,只要您不要求太多。

你说previous 不是一个常数,但这不是 Pylint 使用该术语的方式。您在模块的最外层缩进级别声明previous,因此它是全局的; Pylint 认为全局变量的唯一有效用途是常量。因此出现错误。

要让 pylint 接受任何格式的常量,请在资源配置文件中使用这一行:

const-rgx=[A-Za-z0-9_]{1,30}$

这就是我找到默认设置后所做的,即

const-naming-style=UPPER_CASE

限制太多。

RC 文件很重要,IMO。它使您可以对 Pylint 的功能进行大量控制。如果您的 RC 文件名为 pylint.rc,您可以使用标志 --rcfile=pylint.rc 调用 pylint。根据您的环境设置方式,您可能需要提供完整的路径名。

根据所描述的配置,Pylint 毫无怨言地接受此代码:

previous = ''
for word in ['you', 'cannot', 'be', 'serious']:
    if previous:
        print(previous[0], word)
    previous = word

逻辑相同,但更容易理解,因为它清楚地表明了 previous 是一个字符串。所以 Pylint 确实帮助你编写了更具可读性的代码。

有时还需要告诉 Pylint 停止抱怨某句台词。在您的示例中,如果您真的想在 None 之前初始化,您所要做的就是添加一个内联 pragma,如下所示:

previous = None
for word in ['you', 'cannot', 'be', 'serious']:
    if previous is not None:
        print(previous[0], word)   # pylint: disable=unsubscriptable-object
    previous = word

与您尝试的解决方案相比,这是一种更好的解决方案,因为它只解决了一行中的错误,并且会标记其他出现相同错误的情况。

【讨论】:

  • 感谢您的完整回复。
猜你喜欢
  • 2014-08-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多