我在python上有以下字典:
dictionary = {'key1': 1,
'sub_dict': {'key2': 0}
}
当我在以下行上运行mypy时:
print(dictionary['sub_dict']['key2'])
它引发了错误Value of type "object" is not indexable
静态打字很棘手。 mypy
可以确定dictionary
的值并不都具有相同的类型,但这就是它的范围。 dictionary
的静态类型是Dict[str,object]
,基于初始值。然而,mypy
并没有尝试进一步模拟代码,这意味着它不知道d['sub_dict']
是否仍然是另一个dict
,你试图用key2
索引它,这导致类型错误。
你可以做的一件事是帮助mypy
告诉它使用typing.cast
可以将特定值视为具有特定类型。
print(typing.cast(typing.Dict[str,dict], d['sub_dict'])['key2'])
在运行时,typing.cast
实际上是一个身份函数;它只是返回它的第二个参数。 mypy
将其视为一种更强烈的类型提示,并表示无论以前的任何提示或注释,d['sub_dict']
都应被视为Dict[str,dict]
。
但请注意,通过使用cast
,您告诉mypy
您承担责任确保dictionary['sub_dict']
在运行时实际上是dict
,因为这不是您可以用静态类型传达的东西。你可能会想到类似的东西
dictionary : Dict[str,Union[int,dict]] = ...
会工作,但这只是告诉mypy
写dictionary['foo'] = 'bar'
将是一个类型错误,因为'bar'
既不是int
也不是dict
。即使有更准确的类型提示,mypy
仍然无法知道dictionary
将任何特定键映射到什么类型的值。
你也可以使用Any
:
dictionary: Dict[str,Any] = ...
因为现在你说任何类型都可以用作值,并且可以为索引的结果假定任何类型,并且这两种类型不必排列。也就是说,dictionary['key1'] = 3
很好,因为int
与Any
兼容,但dictionary['sub_dict']['key2']
也很好,因为dictionary['sub_dict']
产生的任何东西也与Any
兼容,你可以认为那种类型本身是可索引的。实际上,它涵盖了代码中任何地方使用dictionary
的任何内容,而不是使用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
本身除了key1
和sub_dict
之外永远不会有任何关键。 (在这个假设的世界中,defaultdict
可以将任意未指定的键映射到默认类型。)