【问题标题】:Tell pylint what the return type of a method is告诉 pylint 方法的返回类型是什么
【发布时间】:2017-12-27 08:07:16
【问题描述】:

提供详细信息:这是一个受限环境,包含 Python 2.7.14、Pylint 1.8.1 和 Astroid 1.6.0 以及各种其他模块,但我无法轻松安装新模块,例如 mypy(甚至使用 virtualenv)或对代码库进行重大更改。

由于https://github.com/PyCQA/pylint/issues/400,我的某些代码的 pylint 出现错误。我已经以一种骇人听闻的方式解决了这个问题(通过删除 wait() 方法的整数参数),现在我没有收到错误,但没有进行检查(pylint 无法确定变量的类型完全没有)。

我真正想做的是告诉 pylint 返回类型是什么。我已经尝试阅读 Astroid 文档,仔细阅读各种 astroid/brains 文件,并查看其他 SO 问题和答案,例如Set multiple inferred types based on arguments for pylint pluginpylint, coroutines, decorators and type inferencing,但我想我只是不明白。我添加了自己的load-plugins,并且我知道它是在 pylint 期间加载的(因为它一开始有语法错误:))。但我只是不确定它需要做什么。

假设我有这个代码:

class Peer(object):
    def get_domain(self):
        return "foo"

class TestListener(object):
    def __init__(self):
        self._latest = None

    def get(self, timeout):
        # tricks here
        return self._latest

    def peer_joined(self, peer):
        self._latest = peer

peer = TestListener().get(3)
print(peer.get_domain())
print(peer.get_foo())

# tricks here 期间,我们确实在等待threading.Event(),在此期间,另一个线程将调用peer_joined() 并传递Peer() 类型的对象,但pylint 并不理解这一点。

我想做的是注释 TestListener.get() 方法告诉 pylint 它将返回一个 Peer 对象,以便 pylint 将在第二次打印调用中捕获错误。

我已经尝试过了,但显然我遗漏了一些基本的东西,因为我的转换方法似乎从未被调用过(如果我调用了一个虚假的方法调用,则不会打印任何错误):

from astroid import MANAGER, register_module_extender
from astroid.builder import AstroidBuilder

def TestListener_transform():
    return AstroidBuilder(MANAGER).string_build('''
class TestListener(object):
    def get(self, timeout):
        return Peer()
''')

register_module_extender(MANAGER, 'TestListener', TestListener_transform)

# for pylint load-plugins
def register(linter):
    pass

【问题讨论】:

  • 我认为 mypy(静态类型)会是一个更好的工具。你考虑过吗?
  • 不幸的是,我处于一个受限制的环境中,无法轻松添加大量新模块,而 pylint 是我可用的。
  • 添加文档字符串没有帮助;请参阅下面的答案。所以我不认为这是重复的。谢谢!

标签: python pylint


【解决方案1】:
def get(self, timeout):
    """
    :param timeout: How many seconds to wait
    :type timeout: int
    :rtype: threading.Event
    """
    # tricks here
    return self._latest

这是一种用于编写 python 文档字符串的 reStructuredText 格式(一个出现在函数定义之后的多行字符串。 您可以在那里记录所有参数类型,以及函数返回的内容及其数据类型。

pylint 可以解析该文档字符串以找出该函数返回值的数据类型。

this stackoverflow answer有更全面的解释 What is the standard Python docstring format?

【讨论】:

  • 虽然此代码 sn-p 可能是解决方案,但 including an explanation 确实有助于提高您的帖子质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。
  • 我同意你的观点,有点懒惰。我已经更新了答案。谢谢yivi
  • 不幸的是,这对我不起作用。对你起作用吗?我用:rtype: Peer 添加了文档字符串,然后在我的pylintrc 文件中启用了pylint.extensions.docparams 插件。我知道它有效,因为它警告我文档字符串中缺少:return: 描述。但是,pylint 仍然没有发出任何关于错误方法peer.get_dom() 的消息。
  • 您可以尝试的另一件事是使用断言。 assert isinstance(peer, Peer) 之前调用peer.get_dom()
  • 嗨@Ramast;不幸的是,这行不通。我试图让 pylint 看到 get() 方法的返回类型是 Peer 对象,以便它可以检查返回对象使用的所有方法等。 Pylint 实际上并不运行代码,它是一个静态类型检查器,因此 assert 没有任何作用。目标是发现代码中的错误,而不必运行代码的所有分支;如果我运行代码,我不需要断言,因为 Python 无论如何都会失败(因为在 Peer 对象中没有 get_dom() 方法)。
【解决方案2】:

要提一提的是 pylint 目前的类型检查能力有限,就像在 mypy.xml 中看到的那样。它更多地依赖于在没有类型提示的情况下推断值和类型,尽管其目的是在某些时候支持 PEP-484 类型。

现在关于这个问题,我看到您正在使用模块扩展器,而实际上您应该使用类转换,如下所示:

astroid.MANAGER.register_transform(astroid.ClassDef,  _class_transform,
                                   optional_transform_predicate)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-07-27
    • 2012-10-31
    • 1970-01-01
    • 1970-01-01
    • 2019-02-03
    • 2017-08-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多