嵌套字典的键入提示

问题描述 投票:0回答:3

我在 Python 脚本中解析的数据结构是一个 json 文件,在

json.load(file_handle)
之后,其类型为
<class 'dict'>
。到目前为止,一切都很好。现在,对于使用它作为输入参数的函数,我想要解析的 json 的类型提示。我在 打字文档 中读到,对于
dict
作为参数,我应该使用
Mapping[key_type, value_type]
:

from typing import Mapping

def foo(json_data: Mapping[str, str]) -> None:
    ...

我解析的 json 具有

str
类型的键和
str
类型的值,但通常情况下,其结构是高度递归的。因此,值更有可能是带有
dict
键的
str
,甚至是这样的
dict
作为值。它是非常嵌套的,直到在最深层,最后一个字典终于有了
str
键和
str
值。

那么如何更精确地表示这个数据结构呢?我在想一些事情,沿着这个问题的思路,它可能是:

Union[Mapping[str, str], Mapping[str, Mapping]]

但它似乎确实只代表了一层递归。有更好的方法来输入提示吗?

python dictionary python-typing
3个回答
16
投票

简单的听写

您可以简单地使用

Mapping[K, V]
作为另一个
Mapping
的值。假设你的 json 看起来像这样:

{
   "person_1": {"money": 1000},
   "person_2": {"money": 1000}
}

在这种情况下,您可以使用如下所示的类型提示:

Mapping[str, Mapping[str, int]]

更难的听写

但是假设你有更复杂的东西,就像这样:

{
    "person_1": {
        "money": 1000,
        "job": "coder",
    }
}

那么你怎么能输入提示呢?你可以使用

Union
(来自打字)来做这样的事情:

Mapping[str, Mapping[str, Union[str, int]]]

但现在我们会遇到像 mypy 这样的工具的问题,认为

our_dict["person_1"]["job"]
具有类型
Union[str, int]

嗯,这并没有错,毕竟我们就是这么告诉它的。在这里可以提供帮助的是来自 typing_extensionsTypedDict

from typing_extensions import TypedDict

class Person(TypedDict):
    money: int
    job: str

# type hint you would use in your function:
Mapping[str, Person]

注意:在Python中3.8

TypedDict
打字

的一部分

8
投票

如今,mypy 和其他类型检查器支持递归定义。 Json 类型的(某种程度上)完整示例是:

import typing as t

JsonType: t.TypeAlias = t.List['JsonValue'] | t.Mapping[str, 'JsonValue']
JsonValue: t.TypeAlias = str | int | float | None | JsonType

def foo(json_data: JsonType) -> None:
    """Your implementation here"""

这应该进行类型检查。


1
投票

我试图在上面的帖子中评论回复,但如果没有足够的声誉,它不会让我(但会让我发布答案)。

我将按照提供的答案vivax进行操作,然后为未知数据添加以下内容:

from typing import Mapping, Any

Mapping[str, Any] # or Mapping[Any, Any] if the keys are also unknown

您还可以通过定义自己的 JSON 类型来获得更多粒度

© www.soinside.com 2019 - 2024. All rights reserved.