2017-05-15 64 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專家邁克爾,非常感謝! –