为什么我得到 mypy no overload variant of "zip" matches argument 错误?

Why do I get mypy no overload variant of "zip" matches argument error?

我有一个 class 方法:

class TimeUtilitiesTestCase():
    def test_date_and_delta(self) -> None:
        """Tests date_and_delta utility method."""
        now = datetime.datetime.now()
        tdelta = datetime.timedelta
        int_tests = (3, 29, 86399, 86400, 86401 * 30)
        date_tests = [now - tdelta(seconds=x) for x in int_tests]
        td_tests = [tdelta(seconds=x) for x in int_tests]
        results = [(now - tdelta(seconds=x), tdelta(seconds=x)) for x in int_tests]
        for test in (int_tests, date_tests, td_tests):
            for arg, result in zip(test, results):
                dtime, delta = humanizer_portugues.time.date_and_delta(arg)
                self.assertEqualDatetime(dtime, result[0])
                self.assertEqualTimedelta(delta, result[1])
        self.assertEqual(humanizer_portugues.time.date_and_delta("NaN"), (None, "NaN"))

我是 运行 严格的 mypy 检查(配置 here),我收到错误:

error: No overload variant of "zip" matches argument
types "object", "List[Tuple[datetime, timedelta]]"  [call-overload]
                for arg, result in zip(test, results):
                                   ^
note: Possible overload variants:
note:     def [_T1, _T2] zip(*iterables: Tuple[_T1, _T2]) -> Tuple[Tuple[_T
1, ...], Tuple[_T2, ...]]
note:     def [_T1, _T2, _T3] zip(*iterables: Tuple[_T1, _T2, _T3]) -> Tupl
e[Tuple[_T1, ...], Tuple[_T2, ...], Tuple[_T3, ...]]
note:     <3 more similar overloads not shown, out of 10 total overloads>

如果您想完全重现错误,您可以使用以下命令克隆分支 strict-mypygit clone -b strict-mypy https://github.com/staticdev/humanizer-portugues.git

我尝试将 results 从列表更改为元组,但此错误并没有消失。

我怎么打错了?


编者注:
可以使用以下最小示例重现此问题:

def bug_repr() -> None:
    ints = [1, 2]
    floats = [3.14, 2.72]
    strings = ['a', 'b']
    for numeric_list in [ints, floats]:
        for number, string in zip(numeric_list, strings):  # <-- error here
            pass

这给出了同样的错误:

main.py:6: error: No overload variant of "zip" matches argument types "object", "List[str]"
main.py:6: note: Possible overload variants:
main.py:6: note:     def [_T1, _T2] zip(*iterables: Tuple[_T1, _T2]) -> Tuple[Tuple[_T1, ...], Tuple[_T2, ...]]
main.py:6: note:     def [_T1, _T2, _T3] zip(*iterables: Tuple[_T1, _T2, _T3]) -> Tuple[Tuple[_T1, ...], Tuple[_T2, ...], Tuple[_T3, ...]]
main.py:6: note:     <3 more similar overloads not shown, out of 10 total overloads>
Found 1 error in 1 file (checked 1 source file)

您可以在 mypy Playground 上复制此内容。

使用您的最小示例:

问题是,MyPy 推断的类型太窄,即 List[int]List[float],因此它无法为 [=15= 推断类型 List of something ].一般来说,当你放入不同的东西时,容器和静态类型安全性存在问题。例如,您输入了一个浮点数和一个整数,那么静态分析如何知道您要取出什么?参见 Docs on Variance

但是您可以声明一个更通用的类型,使用 Union types,声明它可能包含多个类型。

from typing import Union, List

def bug_repr() -> None:
    ints: List[Union[int, float]] = [1, 2]
    floats: List[Union[int, float]] = [3.14, 2.72]
    strings = ['a', 'b']
    for numeric_list in [ints, floats]:
        for number, string in zip(numeric_list, strings):
            pass

或者,您可以将其声明为列表(或序列)而不指定其中的内容:

from typing import List

def bug_repr() -> None:
    ints: List = [1, 2]
    floats: List = [3.14, 2.72]
    strings = ['a', 'b']
    for numeric_list in [ints, floats]:
        for number, string in zip(numeric_list, strings):
            pass

但我不确定在内部循环中为 number 推断出什么类型。

(注意,您也可以使用 Sequence 作为更通用的类型,而不是 List