如何在多个别名上定义递归 Python 类型?

How can I make a recursive Python type defined over several aliases?

我想要这个逻辑类型结构:

from typing import List, Dict, Union

ObjectType = Dict[str, 'EntryType']
ListType = List['EntryType']
EntryType = Union[str, 'ListType', 'ObjectType']

mypy 报告这些错误:

mdl/structure.py:7: error: Cannot resolve name "ObjectType" (possible cyclic definition)
mdl/structure.py:7: error: Cannot resolve name "EntryType" (possible cyclic definition)
mdl/structure.py:8: error: Cannot resolve name "ListType" (possible cyclic definition)
...

有什么方法可以对这种递归数据类型进行编码吗?

我相信我可以内联各个类型,每次都输入完整的定义,以允许递归。我宁愿避免这种情况,因为它体积庞大,而且不太清晰。

mypy 不支持递归类型:https://github.com/python/mypy/issues/731

mypy 无法使用您的类型定义,我知道的任何其他类型检查器也无法使用。内联各个类型会给你无限长的类型定义,因为它是递归的。

递归类型是not yet supported in mypy。虽然他们肯定在路线图上,但我不确定实施工作何时开始。它原定于今年早些时候开始,但语义分析阶段的先决条件重构(它进行了大量内部更改以干净地支持递归类型)最终花费的时间比预期的要长,所以我不确定新的是什么时间表是。也许在下半年左右的某个时候?

您可以研究的一种可能的替代方法是使用 TypedDicts, which let you assign specific types to certain keys. This is particularly useful if you already know ahead of time what the structure of your input dicts will be -- if you know exactly what keys your ObjectTypes will have, and precisely what they'll map to. Libraries like pydantic 如果您更喜欢使用对象而不是字典并且不想编写一堆验证逻辑,那么在这里也很有用。

不过从实用的角度来说,如果您的字典结构确实是自由格式的,那么最好只使用 ObjectType = Dict[str, object]。毕竟,为了准确识别您正在处理的 EntryType,无论如何您都必须添加一些 isinstance 检查以适当缩小类型。因此,虽然从 object 而不是 Union[str, ListType, ObjectType] 开始会有点烦人,但根据您正在做的事情,它可能不会太过分。