【问题标题】:Mypy error - incompatible types in assignmentMypy 错误 - 分配中的类型不兼容
【发布时间】:2017-10-10 04:40:01
【问题描述】:

我的函数看起来像这个简化的代码示例:

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 错误?

【问题讨论】:

    标签: python mypy


    【解决方案1】:

    问题在于 mypy 推断出您的 result 变量的类型是 Dict[str, bool],这是由于您在第 2 行首次对其进行初始化的方式。

    因此,当您稍后尝试插入 str 时,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 的类型安全性稍高一些——使用 Union 将值声明为 strs 或 bools,但仅此而已。这不是完全类型安全的,但至少您仍然可以对您的 dict 进行 一些 检查。

    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,这意味着其他类型检查工具(如 Pycharm 的检查器)没有义务理解这一点。 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 软件包。

    【讨论】:

    • 感谢迈克尔的全面回答!我想我在 mypy 逻辑的某些概念上遇到了困难,但你真的为我澄清了这一点。旁注:当行长度超过 PEP8 允许的 79 个字符时,您知道如何处理内联类型提示 cmets 吗? (这个项目我不能用Python3.6,所以新的变量注解语法对我不可用)
    • @JanRozycki 小心使用type aliases 通常可以帮助缓解这个问题。在键入具有许多参数的函数时,键入您的函数 like this 也很有帮助。
    • TypedDict 在 python 3.8 中被添加到标准库中
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-06-14
    • 1970-01-01
    • 1970-01-01
    • 2021-12-21
    • 2021-06-02
    • 2017-10-14
    相关资源
    最近更新 更多