mypy 错误 - 尽管使用 'Union' 但类型不兼容
mypy error - incompatible type despite using 'Union'
考虑以下代码示例:
from typing import Dict, Union
def count_chars(string) -> Dict[str, Union[str, bool, int]]:
result = {} # type: Dict[str, Union[str, bool, int]]
if isinstance(string, str) is False:
result["success"] = False
result["message"] = "Inavlid argument"
else:
result["success"] = True
result["result"] = len(string)
return result
def get_square(integer: int) -> int:
return integer * integer
def validate_str(string: str) -> bool:
check_count = count_chars(string)
if check_count["success"] is False:
print(check_count["message"])
return False
str_len_square = get_square(check_count["result"])
return bool(str_len_square > 42)
result = validate_str("Lorem ipsum")
当运行 mypy针对此代码时,返回以下错误:
error: Argument 1 to "get_square" has incompatible type "Union[str, bool, int]"; expected "int"
而且我不确定如果不在第一个函数中使用 Dict[str, Any]
作为返回类型或安装 'TypedDict' mypy 扩展,我该如何避免这个错误。 mypy 实际上是 'right',我的任何代码都不是类型安全的,或者这应该被视为 mypy 错误吗?
Mypy 在这里是正确的——如果你的 dict 中的值可以是 strs、ints 或 bools,那么严格来说我们不能假设 check_count["result"]
将始终准确地评估为 int。
您有几种解决方法。第一种方法实际上只是 检查 check_count["result"]
的类型以查看它是否是一个 int。您可以使用断言来做到这一点:
assert isinstance(check_count["result"], int)
str_len_square = get_square(check_count["result"])
...或者可能是一个 if 语句:
if isinstance(check_count["result"], int):
str_len_square = get_square(check_count["result"])
else:
# Throw some kind of exception here?
Mypy 理解断言和 if 语句中这种形式的类型检查(在一定程度上)。
但是,将这些检查散布在您的代码中可能会很乏味。因此,实际上最好放弃使用字典并转而使用 classes.
即定义一个class:
class Result:
def __init__(self, success: bool, message: str) -> None:
self.success = success
self.message = message
...和 return 一个实例。
这个是稍微不方便,如果你的目标是最终return/manipulatejson,你现在需要写代码来转换这个class from/to json,但它确实可以避免与类型相关的错误。
定义自定义 class 可能会有点乏味,因此您可以尝试使用 NamedTuple 类型:
from typing import NamedTuple
Result = NamedTuple('Result', [('success', bool), ('message', str)])
# Use Result as a regular class
你仍然需要编写元组 -> json 代码,并且 iirc namedtuples(来自 collections
模块的常规版本和此类型变体)的性能不如 classes,但也许这对您的用例并不重要。
考虑以下代码示例:
from typing import Dict, Union
def count_chars(string) -> Dict[str, Union[str, bool, int]]:
result = {} # type: Dict[str, Union[str, bool, int]]
if isinstance(string, str) is False:
result["success"] = False
result["message"] = "Inavlid argument"
else:
result["success"] = True
result["result"] = len(string)
return result
def get_square(integer: int) -> int:
return integer * integer
def validate_str(string: str) -> bool:
check_count = count_chars(string)
if check_count["success"] is False:
print(check_count["message"])
return False
str_len_square = get_square(check_count["result"])
return bool(str_len_square > 42)
result = validate_str("Lorem ipsum")
当运行 mypy针对此代码时,返回以下错误:
error: Argument 1 to "get_square" has incompatible type "Union[str, bool, int]"; expected "int"
而且我不确定如果不在第一个函数中使用 Dict[str, Any]
作为返回类型或安装 'TypedDict' mypy 扩展,我该如何避免这个错误。 mypy 实际上是 'right',我的任何代码都不是类型安全的,或者这应该被视为 mypy 错误吗?
Mypy 在这里是正确的——如果你的 dict 中的值可以是 strs、ints 或 bools,那么严格来说我们不能假设 check_count["result"]
将始终准确地评估为 int。
您有几种解决方法。第一种方法实际上只是 检查 check_count["result"]
的类型以查看它是否是一个 int。您可以使用断言来做到这一点:
assert isinstance(check_count["result"], int)
str_len_square = get_square(check_count["result"])
...或者可能是一个 if 语句:
if isinstance(check_count["result"], int):
str_len_square = get_square(check_count["result"])
else:
# Throw some kind of exception here?
Mypy 理解断言和 if 语句中这种形式的类型检查(在一定程度上)。
但是,将这些检查散布在您的代码中可能会很乏味。因此,实际上最好放弃使用字典并转而使用 classes.
即定义一个class:
class Result:
def __init__(self, success: bool, message: str) -> None:
self.success = success
self.message = message
...和 return 一个实例。
这个是稍微不方便,如果你的目标是最终return/manipulatejson,你现在需要写代码来转换这个class from/to json,但它确实可以避免与类型相关的错误。
定义自定义 class 可能会有点乏味,因此您可以尝试使用 NamedTuple 类型:
from typing import NamedTuple
Result = NamedTuple('Result', [('success', bool), ('message', str)])
# Use Result as a regular class
你仍然需要编写元组 -> json 代码,并且 iirc namedtuples(来自 collections
模块的常规版本和此类型变体)的性能不如 classes,但也许这对您的用例并不重要。