You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python类型注解描述任意深度的树形/递归数据结构?

如何用Python Typing描述任意深度的树形递归结构

你碰到的问题很典型——递归数据结构的类型注解不能用...来偷懒,固定层级的嵌套写法也完全没法适配任意深度的场景。好在Python的typing模块提供了完美的解决方案,不需要复杂的自定义泛型类,用自引用类型别名就可以搞定。


核心解决方案:自引用类型别名

你的树形结构本质是每个节点是一个字典,键是Symbol,值是(ndarray, 子树)的元组,子树和当前节点结构完全一致。我们可以通过自引用的类型别名来定义这个递归结构:

Python 3.10+ 写法(推荐)

从Python 3.10开始,类型别名支持字符串形式的自引用,写法非常简洁:

from typing import Dict, Tuple
from sympy.core.symbol import Symbol
import numpy as np

# 定义递归树形结构类型
Tree = Dict[Symbol, Tuple[np.ndarray, 'Tree']]

Python 3.9及以下 兼容写法

如果你的Python版本低于3.10,需要用ForwardRef来显式声明自引用:

from typing import Dict, Tuple, ForwardRef
from sympy.core.symbol import Symbol
import numpy as np

# 先声明ForwardRef,再绑定类型
Tree = ForwardRef('Tree')
Tree.__forward_arg__ = Dict[Symbol, Tuple[np.ndarray, Tree]]

Python 3.11+ 更简洁写法

Python 3.11进一步简化了自引用,不需要加引号,直接写类型别名即可:

from typing import Dict, Tuple
from sympy.core.symbol import Symbol
import numpy as np

Tree = Dict[Symbol, Tuple[np.ndarray, Tree]]

为什么这个写法可行?

  • 避免固定层级:类型别名Tree会递归指向自身,无论树的深度是多少,只要每个节点都符合Dict[Symbol, Tuple[ndarray, Tree]]的结构,就会被类型检查器认可。
  • 支持空字典:你提到字典长度可以为0(对应叶子节点的子树为空),而Dict本身就允许空实例,所以空字典完全符合Tree类型的定义。

示例用法

我们可以创建一个任意深度的树,类型检查器不会报错:

from sympy import Symbol
import numpy as np

# 创建符号和数组
x = Symbol('x')
y = Symbol('y')
z = Symbol('z')

# 构建一个3层的树
tree: Tree = {
    x: (np.array([1, 2]), {
        y: (np.array([3, 4]), {
            z: (np.array([5, 6]), {})  # 最内层子树为空字典
        })
    })
}

# 也可以是只有一层的树(子树为空)
simple_tree: Tree = {x: (np.array([7, 8]), {})}

# 空字典也是合法的Tree类型
empty_tree: Tree = {}

要不要自定义泛型?

其实你不需要自定义泛型类,上面的类型别名已经完全满足需求。不过如果未来你需要扩展这个树形结构(比如允许节点值有不同类型),可以用Generic和TypeVar来实现更灵活的泛型递归结构,但对于你现在的场景,自引用类型别名是最简单高效的方案。

内容的提问来源于stack exchange,提问作者gerrit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:10:13