MyPy / python 类型提示不会捕获可以 return 多种类型的调用函数

MyPy / python type hints doesn't catch called function that can return multiple types

attrgetter 函数可以根据您提供的参数 return 不同的类型。如果你传递一个带有一个项目的迭代器,它将 return 只是一个对象的给定字段;如果你向它传递一个包含多个项目的可迭代对象,它 return 是一个对象的这些字段的元组。

但是,当使用类型提示 + MyPy 时,MyPy 不会发现这种差异(它不会抛出任何错误):

from operator import attrgetter


class OneThing:
    foobar = "hello"
    fields = ['foobar']


class TwoThings:
    foobar = "hello"
    goodbye = "potatoes"
    fields = ['foobar', 'goodbye']


def attrgettertest(thing) -> tuple:
    return attrgetter(*thing.fields)(thing)


def main():
    onething = OneThing()
    twothings = TwoThings()

    t1 = attrgettertest(onething)
    t2 = attrgettertest(twothings)

    print("Attrgettertest on 'onething' returned  {} with type {}".format(
        t1, type(t1)))
    print("Attrgettertest on 'twothings' returned  {} with type {}".format(
        t2, type(t2)))


if __name__ == "__main__":
    main()

并且输出:

$ python attrgettrtest.py 
Attrgettertest on 'onething' returned  hello with type <class 'str'>
Attrgettertest on 'twothings' returned  ('hello', 'potatoes') with type <class 'tuple'>
$ mypy attrgettrtest.py 
$ 

预期的结果是这样的:

import random    

def test() -> tuple:
    if random.choice([0, 1]):
        return ("foo", "bar")
    return "foo"

if __name__ == "__main__":
    for n in range(20):
        print(test())

$ mypy test.py 
test.py:8: error: Incompatible return value type (got "str", expected Tuple[Any, ...])

这是 MyPy 中的错误吗?

似乎这里的问题是 attrgetter 有 return 类型 Any,而 mypy 没有捕捉到这个。

我将其发布到 mypy 存储库并获得以下内容 answer:

I think the problem is that attrgetter has return type Any, so that your code passes. In principle, precise type checking would be difficult in such cases, however, there is a newly added flag --warn-return-any that will issue warnings in such situations (it will be available in 0.480, see PR #2854 for details).