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
的值并非都具有相同的类型,但仅此而已。 dictionary
的static类型是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]] = ...
会起作用,但这只是告诉 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
兼容,您可以假设该类型本身是可索引的。实际上,它涵盖了代码中任何地方 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
本身永远不会有任何键 [=78= 不同于 key1
和 sub_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},
}
我在 python 上有以下字典:
dictionary = {
'key1': 1,
'sub_dict': {'key2': 0},
}
当我 运行 mypy 在以下行时:
print(dictionary['sub_dict']['key2'])
它引发错误 Value of type "object" is not indexable
静态类型很棘手。 mypy
可以确定 dictionary
的值并非都具有相同的类型,但仅此而已。 dictionary
的static类型是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]] = ...
会起作用,但这只是告诉 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
兼容,您可以假设该类型本身是可索引的。实际上,它涵盖了代码中任何地方 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
本身永远不会有任何键 [=78= 不同于 key1
和 sub_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},
}