微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Mypy 指定文字输出

如何解决Mypy 指定文字输出

我的函数返回一个包含两个值的元组,其中一个是具有两个可能值之一的字符串,例如“a”或“b”。这个字符串是从 URL 中检索到的,实际上理论上可以是别的东西——在这种情况下,我会引发一个 Valueerror。但是,似乎 mypy 没有看到我的错误,并且仍然对字符串到文字的转换感到不安。解决这个问题的正确方法是什么?

def _get_listing_info(txt: str) -> Tuple[int,Literal["a","b"]]:
    
    findInfo = re.search(r"ios-app://\d+/item/(\w+)/(\d+)",txt)
    if findInfo is None:
        raise ValueError(f"Failed to establish listing type from `{txt}`")

    
    tp,listting_id = findInfo.group(1),int(findInfo.group(2))
    if tp not in {"a","b"}:
        raise ValueError(tp,url)

    return listting_id,tp

Mypy 提出了一个问题:

类型“tuple[int,str]”的表达式不能赋值给返回类型“Tuple[int,> Literal['a','b']]” 元组条目 2 的类型不正确 类型“str”不能分配给类型“Literal['a','b']” “str”不能分配给类型“Literal['a']” “str”不能分配给类型“Literal['b']”

解决方法

这不起作用的原因是因为 x 是 Literal["a","b"] 仅当 x 等于 "a""b" 并且没有其他字符串强> (see Literal semantics here)。

我可以像这样子类化 str

class CustomStr(str):
    def __eq__(self,other):
        return True

等于一切,包括 "a"。要验证这一点:

>>> "a" == CustomStr()
True

>>> CustomStr() == "a"
True

>>> "b" == CustomStr()
True

>>> CustomStr() == "b"
True

(所以这个 str 最终等于 "a""b",无论是 CustomStr()__eq__ 还是文字串的 {{ 1}} 被调用)

检查此自定义字符串是否等于 __eq__ 不足以使其成为 "a",因为它也等于所有其他字符串,这违反了 Literal["a"] 语义。

一般来说,能够子类化类型并覆盖它们的方法(这在 mypy 中是完全类型安全的)使得基于它们的方法的任何类型的缩小都非常困难。这适用于示例的 Literal 集的 __contains__ / in 方法,以及 {"a","b"}__eq__ / ==

假设,您的示例可以键入检查,如果:

  1. findInfo 以某种方式向 re.search 表明它返回一个类型正好是 mypy 的对象,而不是潜在的子类

  2. 因为您使用了 str literalset 推断 mypy 返回 __contains__ 意味着 { {1}} 是 True,其中包含 __contains__ 中的元素之一(它还假设 == 实现正确,这也是 set 无法保证的任意子类__hash__ mypy 是类型提示返回的)。

但是,mypy 在您的示例中没有利用这些事实中的任何一个。

要使您的示例实际进行类型检查,您可以将其更改为:

str

而且它是 100% 安全的,因为我们知道 re.search 不能返回满足那些 def _get_listing_info(txt: str) -> Tuple[int,Literal["a","b"]]: findInfo = re.search(r"ios-app://\d+/item/(\w+)/(\d+)",txt) if findInfo is None: raise ValueError(f"Failed to establish listing type from `{txt}`") tp,listting_id = findInfo.group(1),int(findInfo.group(2)) if tp == "a": return listting_id,"a" if tp == "b": return listting_id,"b" raise ValueError(tp,"abc") 但最终不是 re.searchCustomStr

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。