pythonmypy检查TypeVar(bound=Union[A,B])的返回类型不会出错,而TypeVar(A,B)会出错

2024-05-23 22:43:09 发布

您现在位置:Python中文网/ 问答频道 /正文

当我以两种不同的方式使用TypeVar时,我一直试图理解它的边界:

  • Enums = TypeVar("Enums", Enum1, Enum2)
  • Enums = TypeVar("Enums", bound=Union[Enum1, Enum2])

以下是我正在使用的代码:

#!/usr/bin/env python3.6

"""Figuring out why enum is saying incompatible return type."""


from enum import IntEnum, EnumMeta
from typing import TypeVar, Union


class Enum1(IntEnum):

    MEMBER1 = 1
    MEMBER2 = 2


class Enum2(IntEnum):

    MEMBER3 = 3
    MEMBER4 = 4


# Enums = TypeVar("Enums", bound=Union[Enum1, Enum2])  # Case 1... Success
Enums = TypeVar("Enums", Enum1, Enum2)  # Case 2... error: Incompatible return value


def _enum_to_num(val: int, cast_enum: EnumMeta) -> Enums:
    return cast_enum(val)


def get_some_enum(val: int) -> Enum1:
    return _enum_to_num(val, Enum1)


def get_another_enum(val: int) -> Enum2:
    return _enum_to_num(val, Enum2)  # line 35

运行mypy==0.770时:

  • Case 1Success: no issues found
  • Case 235: error: Incompatible return value type (got "Enum1", expected "Enum2")

这个案例非常类似于这个问题:Difference between TypeVar('T', A, B) and TypeVar('T', bound=Union[A, B])

答案解释了当使用案例1(bound=Union[Enum1, Enum2])时,以下内容是合法的:

  1. Union[Enum1, Enum2]
  2. Enum1
  3. Enum2

当使用案例2(A, B)时,以下内容是合法的:

  1. Enum1
  2. Enum2

然而,我不认为这个答案可以解释我的问题,我没有使用Union案例

谁能告诉我发生了什么事


Tags: toreturndefvalenumnum案例enums
2条回答

我认为出现错误是因为类型检查器没有足够的信息通过查看输入参数的类型来推断返回类型。尽管操纵性能可能会有所改善

假设您有一个简单的泛型函数:

Enums = TypeVar("Enums", Enum1, Enum2)

def add(x: Enums, y: Enums) -> Enums:
    return x

类型检查器可以通过输入参数的类型推断返回类型:

add(Enum2.MEMBER3, Enum2.MEMBER4) # ok, return Enum2
add(Enum1.MEMBER1, Enum1.MEMBER2) # ok, return Enum1

add(Enum2.MEMBER3, Enum1.MEMBER2) # not ok

再次查看函数_enum_to_num,类型检查器无法推断返回类型,它只是不知道将返回什么类型,因为它不知道cast_enum将返回什么类型:

def _enum_to_num(val: int, cast_enum: EnumMeta) -> Enums:
    return cast_enum(val)

静态类型检查的思想是,它在不执行的情况下评估代码,它调查变量的类型,而不是动态。通过查看cast_enum的类型,即EnumMeta,类型检查器无法判断cast_enum是否返回Enums。看起来它只是假设它将返回Enum1,并在_enum_to_num(val, Enum2)中导致错误

您知道_enum_to_num(val, Enum2)将返回Enum2,因为您知道cast_enumEnum2类型检查器通常不涉及的内容。变量cast_enumEnum2,而cast_enum类型EnumMeta,尽管Enum2类型

通过告诉类型检查器将使用^{}通过cast_enum传递类型,可以解决此问题:

from typing import TypeVar, Union, Type

...

def _enum_to_num(val: int, cast_enum: Type[Enums]) -> Enums:
    return cast_enum(val)

错误将消失,因为现在类型检查器可以推断返回类型

我首先写一些关于mypy看到和报告的内容,然后问这是否是mypy bug

信息:

Incompatible return value type (got "Enum1", expected "Enum2")

这里的意思是,大致上是一个Enum2或其子类型Enum2get_another_enum()的声明返回值。然而,mypy认为函数调用_enum_to_num()返回的是Enum1类型

“大致”部分是因为当类型未绑定,或者是AnyUnion类型时,类型检查会出现异常;但这不适用于本例

Mypy决定_enum_to_num()中的函数cast_enum()返回Enums中列出的第一个类型-我猜作为静态类型检查器,它必须选择一个,这就是它所做的

因此,如果在Enums赋值中切换顺序并写入:

Enums = TypeVar("Enums", Enum2, Enum1)  # Case 2... error: Incompatible return value

然后第35行将成功,但是get_some_enum()中的返回将失败,并显示以下消息:

error: Incompatible return value type (got "Enum2", expected "Enum1")

至于这是否是一个mypy bug,很难说

这里使用type()ininstance()函数没有动态类型错误运行代码也按预期工作

另一方面,Python从不在编译时或运行时检查返回类型:您可以将_enum_to_none()的返回类型更改为None,这对于Python解释器来说仍然有效

接下来的问题是:在mypy强加的静态类型系统中,这是一个bug吗?(我不认为政治公众人物484526或其他数字试图解决这个问题)

更有资格的人应该回答这样一个问题:这是否是一个应该被静态分析器捕获的bug,特别是mypy

请参阅Ken Hung的答案,以了解更为明确并消除mypy错误的方法

相关问题 更多 >