[以两种不同的方式使用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")
这种情况是[[非常,类似于此问题:Difference between TypeVar('T', A, B) and TypeVar('T', bound=Union[A, B])
答案说明了在使用情况1(bound=Union[Enum1, Enum2]
)时,以下情况合法:Union[Enum1, Enum2]
Enum1
Enum2
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)
静态类型检查的思想是,它无需执行就可以评估代码,它研究变量的而不是动态的values。通过查看types
cast_enum
的类型,即EnumMeta
,类型检查器无法判断cast_enum
是否返回Enums
。看起来它只是假设它将返回Enum1
,并在_enum_to_num(val, Enum2)
中引起错误。您知道_enum_to_num(val, Enum2)
将返回Enum2
,因为您知道cast_enum
的value
是Enum2
。 value是type检查器通常不会碰到的东西。可能令人困惑,变量cast_enum
的value是Enum2
,而cast_enum
的type是EnumMeta
,尽管Enum2
是type。 可以通过告诉类型检查器使用cast_enum
通过typing.Type
传递类型来解决此问题:typing.Type
错误将消失,因为现在类型检查器可以推断出返回类型。
消息:
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")
或它的子类型。Enum2
是Enum2
的声明返回值。但是mypy认为函数调用get_another_enum()
返回的是_enum_to_num()
类型。“大致”部分是因为当一个类型是未绑定的,或者是
Enum1
或Any
类型时,存在类型检查的例外;但这不适用于本示例。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的错误。