dict of dict 上的 Mypy 错误:"object" 类型的值不可索引

Mypy error on dict of dict: Value of type "object" is not indexable

我在 python 上有以下字典:

dictionary = {
    'key1': 1,
    'sub_dict': {'key2': 0},
}

当我 运行 mypy 在以下行时:

print(dictionary['sub_dict']['key2'])

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

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

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

print(typing.cast(typing.Dict[str,dict], d['sub_dict'])['key2'])

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

但是请注意,通过使用 cast,您是在告诉 mypy 承担了确保 dictionary['sub_dict'] 是,实际上是运行时的 dict,因为这不是您可以使用静态类型传达的内容。你可能会认为

dictionary : Dict[str,Union[int,dict]] = ...

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

您也可以使用 Any

dictionary: Dict[str,Any] = ...

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


主要题外话:有一个概念依赖类型,最简单的例子是像PositiveInt这样的类型,它与int相同除了它不允许负值。 dictionary 似乎具有类似的依赖类型,其中值的类型实际上是存储在值中的实际数据的函数。例如,假设您可以使用 dict 实例 Dict 来指定其值的类型。

dictionary: Dict[str, {"key1": int, "sub_dict": dict}] = {'key1': 1,
          'sub_dict': {'key2': 0}
         }

现在,不仅 mypy 可以告诉 dictionary['key1'] 应该是一个 int,而且 dictionary 本身永远不会有任何键 [=78= 不同于 key1sub_dict。 (在这个假设的世界中,defaultdict 可以将任意未指定的键映射到默认类型。)

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

from typing import Any, Dict

dictionary: Dict[str, Any] = {
    'key1': 1,
    'sub_dict': {'key2': 0},
}

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

具体到 OP 的字典,下面的可能更合适。

from typing import Tuple, Dict

dictionary: Dict[str, Tuple[int, Dict]] = {
    'key1': 1,
    'sub_dict': {'key2': 0},
}