Mypy 错误 "Need more than 2 values to unpack (3 expected)" 尽管使用了不同元组的并集

Mypy error "Need more than 2 values to unpack (3 expected)" although union of different tuples is used

当我 运行 mypy 使用以下代码时,我得到

Need more than 2 values to unpack (3 expected)

我该如何解决这个问题?

def func(third: bool = False) -> tuple[int, int] | tuple[int, int, int]:
    if third:
        return 1, 2, 3
    else:
        return 1, 2
        
a, b, c = func(True) # mypy error line
在这种情况下,

func 实际上返回了三个值。我正在使用 Python 3.10.4.

这是 Mypy 的一个已知问题:Cannot unpack Union of Tuples of different length

这是我如何修复给定示例的建议,因此它可以工作并且 Mypy 没有显示错误:

from typing import Optional, Tuple


def func(third: bool = False) -> Tuple[int, int, Optional[int]]:
    if third:
        return 1, 2, 3
    else:
        return 1, 2, None


a, b, c = func(True)

print(a, b, c)

输出:

1 2 3

Mypy运行:

Success: no issues found in 1 source file

您可以使用 overload 来声明 func 具有不同的 return 类型,具体取决于参数。

from typing import Literal, overload

@overload
def func(third: Literal[True]) -> tuple[int, int, int]:
    ...
@overload
def func(third: Literal[False]) -> tuple[int, int]:
    ...
def func(third: bool = False):
    if third:
        return 1, 2, 3
    else:
        return 1, 2

描述的情况是 overloading 的典型用例。

您可以注释该函数,这样对于 True 参数它是 return 的 3 元组和对于 False - 2 元组:

from typing import overload, Literal

@overload
def func(third: Literal[True]) -> tuple[int, int, int]: 
    ...
@overload
def func(third: Literal[False] = ...) -> tuple[int, int]:
    ...
    
def func(third: bool = False) -> tuple[int, int] | tuple[int, int, int]:
    if third:
        return 1, 2, 3
    else:
        return 1, 2
        
a, b, c = func(True)
a, b = func(False)
a, b = func()

Playground

您当前代码中的问题是 mypy 不知道 return 类型是二元组还是三元组。它不会对实现做出额外的假设,类型提示是严格的。您的代码可能如下所示(mypy 以完全相同的方式解释):

import random
def func(three: bool = False) -> tuple[int, int] | tuple[int, int, int]:
    if random.random() < 0.5:
        return 1, 1
    else:
        return 1, 1, 1

a, b, c = func()

... 现在您的代码在(大约)50% 的情况下失败并且 mypy 指向该错误。