dict 的 dict 上的 Mypy 错误:“对象”类型的值不可索引

Pie*_* S. 8 python dictionary mypy

我在 python 上有以下字典:

dictionary = {
    'key1': 1,
    'sub_dict': {'key2': 0},
}
Run Code Online (Sandbox Code Playgroud)

当我在以下行上运行 mypy 时:

print(dictionary['sub_dict']['key2'])
Run Code Online (Sandbox Code Playgroud)

它引发了错误 Value of type "object" is not indexable

che*_*ner 17

静态类型很棘手。mypy可以确定dictionary并非所有的值都具有相同的类型,但仅此而已。的静态类型dictionaryDict[str,object],基于初始值。但是,mypy不会尝试进一步模拟代码,这意味着它不知道在您尝试使用 对其进行索引时d['sub_dict']是否仍然是另一个代码,这会导致类型错误。dictkey2

您可以做的一件事是mypy通过告诉它可以将特定值视为具有特定类型来提供帮助,使用typing.cast.

print(typing.cast(typing.Dict[str,dict], d['sub_dict'])['key2'])
Run Code Online (Sandbox Code Playgroud)

在运行时,typing.cast实际上是一个身份函数;它只是返回它的第二个参数。mypy将其视为更强的类型提示,即无论之前有任何提示或注释,d['sub_dict']都应将其视为Dict[str,dict].

但是请注意,通过使用cast,你告诉mypy那个正在承担对保证责任dictionary['sub_dict'],事实上,一个dict在运行时,由于这不是东西,你可以用一个静态类型传达。你可能认为像

dictionary : Dict[str,Union[int,dict]] = ...
Run Code Online (Sandbox Code Playgroud)

会起作用,但这只是说明mypywrite 将是一个类型错误dictionary['foo'] = 'bar',因为'bar'既不是 an 也不是inta dict。即使有更准确的类型提示,仍然无法mypy知道dictionary将任何特定键映射到什么类型的值。

你也可以使用Any

dictionary: Dict[str,Any] = ...
Run Code Online (Sandbox Code Playgroud)

因为现在你是说任何类型都可以作为值,索引的结果可以假设任何类型,这两种类型不必对齐。也就是说,dictionary['key1'] = 3很好,因为int与 兼容Any,但dictionary['sub_dict']['key2']也很好,因为无论dictionary['sub_dict']产生什么与 兼容Any,并且您可以假设该类型本身是可索引的。实际上,它涵盖了代码中任何地方的任何使用dictionary,而不是您用来cast断言应该允许什么的特定位置。


主要离题:有一个依赖类型的概念,其中最简单的例子是类似的类型PositiveIntint除了不允许负值之外,它与其他类型相同。dictionary似乎具有类似的依赖类型,其中值的类型实际上是存储在值中的实际数据的函数。例如,想象一下,如果你可以使用一个实例dictDict指定其值的类型。

dictionary: Dict[str, {"key1": int, "sub_dict": dict}] = {'key1': 1,
          'sub_dict': {'key2': 0}
         }
Run Code Online (Sandbox Code Playgroud)

现在,不仅可以mypy告诉大家,dictionary['key1']应该是一个int,但dictionary本身不能有任何按键其他key1sub_dict。(在这个假设的世界中, adefaultdict可以将任意未指定的键映射到默认类型。)


ror*_*noa 6

对我有用的一个简单的改变是这样的。

from typing import Any, Dict

dictionary: Dict[str, Any] = {
    'key1': 1,
    'sub_dict': {'key2': 0},
}
Run Code Online (Sandbox Code Playgroud)

这告诉 mypy 你的字典的值可以是任何类型。如果您的值可以有不同的种类(整数、浮点数、字符串、字典等),那么您最好使用Any类型注释。

具体来说,对于OP的字典,以下内容可能更合适。

from typing import Union, Dict

dictionary: Dict[str, Union[int, Dict]] = {
    'key1': 1,
    'sub_dict': {'key2': 0},
}
Run Code Online (Sandbox Code Playgroud)