2017-05-15 21 views
1

다음 사항을 고려 코드 샘플 사용에도 불구하고 호환되지 않는 유형 :mypy 오류 - '연합'

error: Argument 1 to "get_square" has incompatible type "Union[str, bool, int]"; expected "int" 

와 잘 모르겠어요 :이 코드에 대해 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") 

, 다음과 같은 오류가 반환됩니다 Dict[str, Any]을 첫 번째 함수에서 반환 된 형식으로 사용하거나 'TypedDict'mypy 확장을 설치하지 않고이 오류를 피할 수있는 방법. mypy가 실제로 '옳은가요', 모든 코드가 유형이 안전하지 않습니까, 아니면 mypy 버그로 간주되어야합니까?

답변

1

여기에서 Mypy가 정확합니다. dict의 값이 strs, ints 또는 bool 일 수있는 경우 엄밀히 말하면 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 모듈 및이 유형화 된 변형)은 클래스보다 성능이 낮지 만 유스 케이스는 중요하지 않습니다.

+0

당신은 진짜 미시적 인 전문가입니다. Michael, 많은 감사합니다! –