我被卡住了,试图理解 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 1
Success: no issues found
Case 2
: 35: error: Incompatible return value type (got "Enum1", expected "Enum2")
:: 此案是 很 与本题类似。TypeVar('T', A, B)和TypeVar('T', bound=Union[A, B])之间的区别。
答案解释当使用案例1(bound=Union[Enum1, Enum2]
),以下是合法的。
Union[Enum1, Enum2]
Enum1
Enum2
而当使用案例2时A, B
),下面的内容是合法的。
Enum1
Enum2
但是,我不认为这个答案能解释我的问题,我没有使用... ... Union
的情况。
谁能告诉我这是怎么回事?
我认为错误的发生是因为类型检查器没有足够的信息来检查 推断 通过查看输入参数的类型来确定返回类型。虽然处理方式可能会有所改进。
假设你有一个简单的通用函数。
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_enum
是 Enum2
. 该 价值 是什么 类型 检查器一般不碰。这可能会让人感到困惑。价值 变化的 cast_enum
是 Enum2
而 类型 的 cast_enum
是 EnumMeta
虽 Enum2
是一个 类型.
这个问题可以通过告诉类型检查器,类型将通过 cast_enum
使用 typing.Type
:
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
的子类型。Enum2
的声明返回值。get_another_enum()
. 然而,mypy认为函数调用 _enum_to_num()
正在返回一个 Enum1
类型。
大概 "的部分是因为当一个类型是未绑定的,或者是一个 Any
或 Union
类型;但在本例中并不适用。
Mypy决定将函数 cast_enum()
在 _enum_to_num()
正在返回 第一 型 Enums
- 我想作为一个静态类型检查器,它必须选择一个,这就是它的工作。
所以如果你把 Enums
赋值并写入。
Enums = TypeVar("Enums", Enum2, Enum1) # Case 2... error: Incompatible return value
那么第35行就会成功,但在第35行中的回车就会成功。get_some_enum()
会出现失败的信息。
error: Incompatible return value type (got "Enum2", expected "Enum1")
至于这是不是mypy的错误,很难说... ...
这里没有动态类型的错误,你可以通过使用 type()
或 ininstance()
职能。运行 的代码也能正常工作。
另一方面,Python 从不检查返回类型,不管是在编译时还是在运行时:你可以改变一下 _enum_to_none()
将要 None
而就 Python 解释器而言,这仍然是有效的。
那么问题就来了:在mypy强加的静态类型系统中,这是不是一个bug?(我不认为PEP 484、526或其他数字试图解决这个问题)。
应该有更有资格的人回答这个问题,这是否是一个应该被静态分析器,尤其是mypy抓住的bug。
请看Ken Hung的回答,他的回答可以更明确,并删除mypy的错误。