我的函数返回一个由两个值组成的元组,其中一个值是包含两个可能值之一的字符串,例如“a”或“b”。这个字符串是从URL中检索到的,实际上理论上可以是其他的东西——在这种情况下,我会提出一个Valuerror。然而,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提出了一个问题:
Expression of type "tuple[int, str]" cannot be assigned to return type "Tuple[int, > Literal['a', 'b']]" Tuple entry 2 is incorrect type Type "str" cannot be assigned to type "Literal['a', 'b']" "str" cannot be assigned to type "Literal['a']" "str" cannot be assigned to type "Literal['b']"
这不起作用的原因是,只有当} semantics here )时,x才是
x
等于"a"
或"b"
且没有其他字符串(see ^{Literal["a", "b"]
我可以这样子类
str
:它等于一切,包括
"a"
。要验证这一点,请执行以下操作:(因此,不管是调用
CustomStr()
的__eq__
还是文字字符串的__eq__
,这个str
最终都等于"a"
和"b"
)检查此自定义字符串是否等于
"a"
不足以使其成为Literal["a"]
,因为它也等于其他所有字符串,这违反了Literal
语义一般来说,能够对类型进行子类化并重写它们的方法(在mypy中是完全类型安全的)使得基于它们的方法的任何类型的缩小都非常困难。这适用于示例的
{"a", "b"}
集的__contains__
/in
方法,以及findInfo
的__eq__
/==
假设您的示例可以进行类型检查,如果:
re.search
以某种方式指示mypy
它返回一个类型恰好为str
的对象,而不是潜在的子类由于使用了
set
文字,mypy
推断__contains__
返回True
意味着__contains__
的参数是==
,其中有一个元素在set
中(该元素也假定__hash__
正确实现,同样mypy
无法保证str
的任意子类的re.search
是提示返回的类型)然而,mypy在您的示例中没有利用这两个事实
要使示例真正进行类型检查,可以将其更改为:
它是100%安全的,因为我们知道
re.search
不能返回满足这些==
的CustomStr
,但最终不是"a"
相关问题 更多 >
编程相关推荐