Ошибка Mypy - несовместимые типы в присваивании

Моя функция выглядит следующим образом:

def my_func() -> dict:
    result = {"success": False}

    if condition:
        result["success"] = True
        return result
    else:
        result["message"] = "error message"
    return result

Когда я запускаю Mypy (версия 0.52), я получаю эту ошибку:

error: Incompatible types in assignment (expression has type "str", target has type "bool")

и ошибка указывает на вторую последнюю строку в моем примере кода. Почему mypy возвращает эту ошибку? мой код неверен (каким-либо образом) или это какая-то ошибка MyPy?

1 ответ

Решение

Проблема в том, что Mypy предположил, что тип вашего result переменная Dict[str, bool] из-за того, как вы сначала инициализировали его в строке 2.

Следовательно, когда вы пытаетесь вставить строку позже, mypy (по праву) жалуется. У вас есть несколько вариантов исправления кода, которые я перечислю в порядке убывания типа для большинства.

Вариант 1 - объявить ваш словарь так, чтобы его значения имели тип Any - то есть ваши значения вообще не будут проверяться типом:

from typing import Any, Dict

def my_func(condition: bool) -> Dict[str, Any]:
    result = {"success": False}  # type: Dict[str, Any]

    if condition:
        result["success"] = True
    else:
        result["message"] = "error message"
    return result

Обратите внимание, что нам нужно аннотировать вашу вторую строку, чтобы дать mypy подсказку о том, какой тип result должно быть, чтобы помочь процессу вывода.

Если вы используете Python 3.6+, вы можете аннотировать эту строку, используя следующий альтернативный синтаксис, который использует переменные аннотации (которые являются новыми с Python 3.6):

result: Dict[str, Any] = {"success": False}

Вариант 2 немного более безопасен для типов - объявите ваши значения как strs или bools, но не более того, используя Union, Это не совсем безопасно, но, по крайней мере, у вас все еще могут быть некоторые проверки вашего диктата.

from typing import Any, Dict

def my_func(condition: bool) -> Dict[str, Union[str, bool]]:
    result = {"success": False}  # type: Dict[str, Union[str, bool]]

    if condition:
        result["success"] = True
    else:
        result["message"] = "error message"
    return result

Возможно, вы обнаружите, что эта аннотация типа немного длинная / раздражающая для типа, поэтому вы можете использовать псевдонимы типов для удобства чтения (и, возможно, использовать синтаксис переменной аннотации), например, так:

ResultJson = Dict[str, Union[str, bool]]

def my_func(condition: bool) -> ResultJson
    result: ResultJson = {"success": False}
    # ...snip...

Вариант 3 является наиболее безопасным для типов, хотя он требует использования экспериментального типа "TypedDict", который позволяет назначать определенные типы различным полям в вашем dict. Тем не менее, используйте этот тип на свой страх и риск - AFAIK он еще не был добавлен в PEP 484, что означает, что другие инструменты проверки типа (такие как средство проверки Пихарма) не обязаны это понимать. Сама Mypy только недавно добавила поддержку TypedDict, и поэтому все еще может содержать ошибки:

from typing import Optional
from mypy_extensions import TypedDict

ResultJson = TypedDict('ReturnJson', {'success': bool, 'message': Optional[str]})

def my_func(condition: bool) -> ResultJson:
    result = {"success": False, "message": None}  # type: ResultJson

    if condition:
        result["success"] = True
    else:
        result["message"] = "error message"
    return result

Обязательно установите mypy_extensions пакет, если вы хотите использовать эту опцию.

Другие вопросы по тегам