Mypy 错误 - 分配中的类型不兼容

Posted

技术标签:

【中文标题】Mypy 错误 - 分配中的类型不兼容【英文标题】:Mypy error - incompatible types in assignment 【发布时间】: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 错误?

【问题讨论】:

【参考方案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 中被添加到标准库中

以上是关于Mypy 错误 - 分配中的类型不兼容的主要内容,如果未能解决你的问题,请参考以下文章

django,mypy:查询集,选择。错误:不兼容的类型

mypy 错误 - 尽管使用了“Union”,但类型不兼容

mypy 错误:返回值类型不兼容(得到“object”,预期“Dict [Any, Any]”)

将空元组分配给专用变量时的类型不兼容

从二维数组中的“char *”类型错误分配给“char [100] [100]”类型时的类型不兼容

使用 mypy 检查类型时有啥问题