如何解决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__
/ ==
。
假设,您的示例可以键入检查,如果:
-
findInfo
以某种方式向re.search
表明它返回一个类型正好是mypy
的对象,而不是潜在的子类 -
因为您使用了
str
literal,set
推断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.search
的 CustomStr
。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。