2017-05-15 41 views
1

请考虑下面的代码示例: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错误?

回答

1

Mypy在这里是正确的 - 如果您的字典中的值可以是strs,ints或bools,那么严格来说,我们不能假设check_count["result"]将始终评估为整数。

您有几种解决方法。第一种方法实际上只是检查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语句(在有限的范围)。

但是,在整个代码中散布这些检查可能令人乏味。因此,最好实际上放弃使用字典并切换到使用类。

也就是说,定义一个类:

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模块和这种类型的变体)性能较低,然后类,但也许这对你的用例无关紧要。

+0

你是一个真正的mypy专家迈克尔,非常感谢! –