枚举导致类型不兼容的 mypy 错误

enumerate causes incompatible type mypy error

以下代码:

from typing import Union


def process(actions: Union[list[str], list[int]]) -> None:
    for pos, action in enumerate(actions):
        act(action)


def act(action: Union[str, int]) -> None:
    print(action)

生成 mypy 错误: Argument 1 to "act" has incompatible type "object"; expected "Union[str, int]"

然而,当删除枚举函数时,输入没问题:

from typing import Union


def process(actions: Union[list[str], list[int]]) -> None:
    for action in actions:
        act(action)


def act(action: Union[str, int]) -> None:
    print(action)

有谁知道枚举函数正在做什么来影响类型? 这是 python 3.9 和 mypy 0.921

我不知道它是如何影响类型的。我知道使用 len() 可以以相同的方式工作。它速度较慢,但​​如果它解决了问题,那可能是值得的。抱歉帮不上什么忙

似乎 mypy 无法推断类型并概括为对象。可能值得在他们身边提出一个问题。作为解决方法,您可以注释 'action'。这将消除错误。如果您从 typing 导入(遗留)List 是否有效?

enumerate.__next__ 需要比 return 类型比 Tuple[int, Any] 更具体的可用上下文,所以我相信 mypy 本身需要修改才能使enumerate(actions) 产生 Tuple[int,Union[str,int]] 个值的推论。

在此之前,您可以显式转换 action 的值,然后再将其传递给 act

from typing import Union, cast

StrOrInt = Union[str, int]

def process(actions: Union[list[str], list[int]]) -> None:
    for pos, action in enumerate(actions):
        act(cast(StrOrInt, action))


def act(action: Union[str, int]) -> None:
    print(action)

您还可以使 process 通用(现在我想到了,这可能是一个更好的主意,因为它避免了在运行时调用 cast 的开销)。

from typing import Union, cast, Iterable, TypeVar

T = TypeVar("T", str, int)

def process(actions: Iterable[T]) -> None:
    for pos, action in enumerate(actions):
        act(action)


def act(action: T) -> None:
    print(action)

这里,T 不是类型的联合,而是一个单一的具体类型,其标识由对 process 的调用确定。 Iterable[T]Iterable[str]Iterable[int],具体取决于您传递给 process 的类型。这为 process 的其余调用修复了 T,每次对 act 的调用都必须采用相同类型的参数。

Iterable[str]Iterable[int] 是一个有效参数,在过程中将 T 绑定到 intstr。现在 enumerate.__next__ 显然 可以 有特定的 return 类型 Tuple[int, T].