对TypeVar(bound = Union [A,B])的返回类型进行Python mypy检查不会出错,而对TypeVar(A,B)的返回类型则会出错

问题描述 投票:4回答:2

[以两种不同的方式使用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])时,以下情况合法:

    Union[Enum1, Enum2]
  1. Enum1
  2. Enum2
  • 并且在使用情况2(A, B)时,以下内容合法:

      Enum1
  • Enum2

  • 但是,我认为此答案不能解释我的问题,我没有使用Union情况。

    谁能告诉我发生了什么事?

  • python generics static-analysis mypy
    2个回答
    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)

    静态类型检查的思想是,它无需执行就可以评估代码,它研究变量的

    types

    而不是动态的values。通过查看cast_enum的类型,即EnumMeta,类型检查器无法判断cast_enum是否返回Enums。看起来它只是假设它将返回Enum1,并在_enum_to_num(val, Enum2)中引起错误。您知道_enum_to_num(val, Enum2)将返回Enum2,因为您知道cast_enum

    value

    Enum2valuetype检查器通常不会碰到的东西。可能令人困惑,变量cast_enumvalueEnum2,而cast_enumtypeEnumMeta,尽管Enum2type可以通过告诉类型检查器使用cast_enum通过typing.Type传递类型来解决此问题:

    typing.Type

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

    1
    投票
    我先写一些关于mypy的见解和报告,然后再问这是否是mypy bug。

    消息:

    from typing import TypeVar, Union, Type ... def _enum_to_num(val: int, cast_enum: Type[Enums]) -> Enums: return cast_enum(val)

    这里的意思是大致期望Incompatible return value type (got "Enum1", expected "Enum2")
    或它的子类型。 Enum2Enum2的声明返回值。但是mypy认为函数调用get_another_enum()返回的是_enum_to_num()类型。 

    “大致”部分是因为当一个类型是未绑定的,或者是Enum1Any类型时,存在类型检查的例外;但这不适用于本示例。

    Mypy判断Union中的函数cast_enum()返回_enum_to_num()中列出的

    first类型-我想作为静态类型检查器,它必须选择一个,这就是它的作用。

    因此,如果您在Enums分配中切换顺序并输入:

    Enums

    然后第35行将成功,但是Enums = TypeVar("Enums", Enum2, Enum1)  # Case 2... error: Incompatible return value
    中的返回将失败,并显示以下消息:

    get_some_enum()

    关于这是否是mypy错误,很难告诉...

    没有动态类型错误,您可以使用error: Incompatible return value type (got "Enum2", expected "Enum1") type()函数在此处找到;

    running该代码也可以正常工作。

    [另一方面,Python从不检查返回类型,无论是在编译时还是在运行时:您可以将ininstance()的返回类型更改为_enum_to_none(),并且对于Python解释器而言仍然有效。有关。

    然后问题归结为:在mypy施加的静态类型系统中,这是一个错误吗? (我不认为PEP 484、526或其他数字会尝试解决这一问题)。

    更有资格的人应该回答这个问题是否应该由静态分析器(特别是mypy捕获)的问题。

    请参阅Ken Hung的答案以更明确地消除mypy的错误。

    © www.soinside.com 2019 - 2024. All rights reserved.