有适合字符串键控的嵌套JSONish dict的python类型注释吗?

有适合字符串键控的嵌套JSONish dict的python类型注释吗?,python,Python,我想在我的项目中输入注释某些数据结构,这些数据结构是解码一些JSON数据的结果 叶很简单: ValueType = Union[int,str,float] 键只是字符串,所以这也很简单: str 但是问题是我的结构可以嵌套,所以我想做如下的事情(但是没有明显失败的自引用): 我想我可以在一个循环中构建一些东西,但这样做(疯狂)通常会破坏类型注释的意义,因为NestedDictType的结构不能静态确定 from typing import Mapping, Type, Union Val

我想在我的项目中输入注释某些数据结构,这些数据结构是解码一些JSON数据的结果

叶很简单:

ValueType = Union[int,str,float]
键只是字符串,所以这也很简单:

str
但是问题是我的结构可以嵌套,所以我想做如下的事情(但是没有明显失败的自引用):

我想我可以在一个循环中构建一些东西,但这样做(疯狂)通常会破坏类型注释的意义,因为NestedDictType的结构不能静态确定

from typing import Mapping, Type, Union

ValueType = Union[int, str, float]


def make_nested_dict_type(depth: int) -> Type:
    # Does not actually work, sorry!
    valueType = Union[make_nested_dict_type(depth - 1)] if depth else ValueType
    return Mapping[str, valueType]


NestedDictType: Type = make_nested_dict_type(4)

foo: NestedDictType = {"a": {"b": {"c": 3, "d": "four", "e": 5.6}}}
那么,我怎样才能简洁地编写这种类型的注释呢?

我专门为此编写了一个库。使用NamedTuple、DataClass或Attr

class A(NamedTuple):
    field: str
    field_2: int
    field_3: Tuple[int, ...]

class B(NamedTuple):
    field: A

@dataclass
class C:
    field: B
然后我使用我的库将dicts/list转换为这些类,反之亦然

typedload.load(data, C)
typedload.dump(data)

从Python 3.7开始,这似乎不是100%实用的:

键入系统可以定义递归类型结构(使用字符串前向引用),但是,MyPy和PyCharm处理类型的递归部分,就像它们是Any一样

我能得到的最接近的方法是手动将递归类型扩展到多个级别。这里有一个部分成功的例子

import datetime
from typing import Mapping, Union, Any

# Recursive structure has been manually expanded to 3 levels, with the forward ref removed.
NestedDictType = Mapping[str,Union[int,str,float,Mapping[str,Union[int,str,float,Mapping[str,Union[int,str,float,Any]]]]]]


# MyPy correctly determines that this is valid
foo: NestedDictType = {"a": {"b": {"c": 3, "d": "four", "e": datetime.date.today()}}}

# MyPy correctly determines that this is bogus
bar: NestedDictType = {"a": datetime.date.today()}

# MyPy cannot detect the error because it's > 3 depth
baz: NestedDictType = {"a":{"b":{"c":{"d":datetime.date.today()}}}}

嘿,你能告诉我们你的JSON数据的格式和你想要的数据结构的示例吗?
mypy
还不支持递归类型。否则,您可以使用正向引用:
NestedDictType=Mapping[str,Union[“NestedDictType”,ValueType]]
。我认为@chepner提供了一个不幸的答案——提供这个注释没有意义,因为没有任何东西可以验证它。呃,看看我的回答。根据类型化/可验证的数据类型构造代码,然后在转换为json或从json转换为json时,使用执行运行时检查的typedload。如果没有指向库的链接,这并不能真正回答问题。
import datetime
from typing import Mapping, Union, Any

# Recursive structure has been manually expanded to 3 levels, with the forward ref removed.
NestedDictType = Mapping[str,Union[int,str,float,Mapping[str,Union[int,str,float,Mapping[str,Union[int,str,float,Any]]]]]]


# MyPy correctly determines that this is valid
foo: NestedDictType = {"a": {"b": {"c": 3, "d": "four", "e": datetime.date.today()}}}

# MyPy correctly determines that this is bogus
bar: NestedDictType = {"a": datetime.date.today()}

# MyPy cannot detect the error because it's > 3 depth
baz: NestedDictType = {"a":{"b":{"c":{"d":datetime.date.today()}}}}