mypy错误 - 尽管使用了' Union'

时间:2017-05-15 14:29:10

标签: python types typechecking typing mypy

请考虑以下代码示例:

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实际上是对的,我的代码是不安全的,还是应该被视为mypy bug?

1 个答案:

答案 0 :(得分:5)

Mypy在这里是正确的 - 如果你的dict中的值可以是strs,int或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语句(在有限范围内)对此表单的类型检查。

然而,在整个代码中,这些检查可能会非常繁琐。因此,最好实际上放弃使用dicts并切换到使用类。

即定义一个类:

class Result:
    def __init__(self, success: bool, message: str) -> None:
        self.success = success
        self.message = message

...而是返回一个实例。

这个 稍微不方便,如果你的目标是最终返回/操作json,你现在需要编写代码来将这个类从/转换为json,但它确实让你避免类型相关的错误。

定义自定义类可能会稍微繁琐,因此您可以尝试使用NamedTuple类型:

from typing import NamedTuple
Result = NamedTuple('Result', [('success', bool), ('message', str)])
# Use Result as a regular class

你仍然需要写元组 - > json代码和iirc namedtuples(来自collections模块的常规版本和这种类型的变体)的性能低于类,但这对您的用例可能并不重要。