为了账号安全,请及时绑定邮箱和手机立即绑定

Python mypy 检查 TypeVar(bound=Union[A, B]) 的返回类型不会

Python mypy 检查 TypeVar(bound=Union[A, B]) 的返回类型不会

慕莱坞森 2022-10-18 16:08:06
我被困在试图理解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, EnumMetafrom typing import TypeVar, Unionclass Enum1(IntEnum):    MEMBER1 = 1    MEMBER2 = 2class Enum2(IntEnum):    MEMBER3 = 3    MEMBER4 = 4# Enums = TypeVar("Enums", bound=Union[Enum1, Enum2])  # Case 1... SuccessEnums = TypeVar("Enums", Enum1, Enum2)  # Case 2... error: Incompatible return valuedef _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 foundCase 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]Enum1Enum2并且在使用案例 2 ( A, B) 时,以下是合法的:Enum1Enum2但是,我认为这个答案不能解释我的问题,我没有使用这种Union情况。谁能告诉我发生了什么事?
查看完整描述

2 回答

?
慕虎7371278

TA贡献1802条经验 获得超4个赞

我认为发生错误是因为类型检查器没有足够的信息来通过查看输入参数的类型来推断返回类型。虽然处理可能会有所改善。


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


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,因为你知道is的值。该值是类型检查器通常不会触及的东西。可能会造成混淆,变量的值是,而类型是,虽然是类型。cast_enumEnum2cast_enumEnum2cast_enumEnumMetaEnum2


这个问题可以通过告诉类型检查器类型将通过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)

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


查看完整回答
反对 回复 2022-10-18
?
aluckdog

TA贡献1847条经验 获得超7个赞

我首先写一点关于 mypy 看到和报告的内容,然后提出这是否是 mypy 错误的问题。

消息:

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

这里的意思是粗略地认为它的一个Enum2或一个子类型是预期的。Enum2是声明的返回值get_another_enum()。但是 mypy 认为函数调用_enum_to_num()正在返回一个Enum1类型。

Any“大致”部分是因为当类型未绑定、或为、或类型时,类型检查存在异常Union;但这不适用于此示例。

Mypy 决定cast_enum()in中的函数_enum_to_num()返回列出的第一个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()使用orininstance()函数在这里找不到动态类型错误;运行代码也按预期工作。

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

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

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

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



查看完整回答
反对 回复 2022-10-18
  • 2 回答
  • 0 关注
  • 411 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号