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

使用anytree根据DataFrame父子关系构建树时重复子节点丢失如何解决

使用anytree生成脚本依赖树时重复子节点丢失问题

我当前尝试基于存储了需按特定顺序执行的脚本的DataFrame生成树图,脚本执行顺序由parent/child关系决定,但生成结果中的子节点数量不正确。我的DataFrame如下所示:
【DataFrame结构示意图】
目前我已编写的代码如下:

from anytree import Node, RenderTree
def add_nodes(nodes, parent, child):
    if parent not in nodes:
        nodes[parent] = Node(parent)
    if child not in nodes:
        nodes[child] = Node(child)
    nodes[child].parent = nodes[parent]

nodes = {}
for parent, child in zip(df["parent_script"],df["child_script"]):
    add_nodes(nodes, parent, child)

roots = list(df[~df["parent_script"].isin(df["child_script"])]["parent_script"].unique())
for root in roots:
    for pre, _, node in RenderTree(nodes[root]):
        print("%s%s" % (pre, node.name))

运行后3个根节点和多个父节点都能正常展示,但子节点只要被添加过一次之后就会丢失。我得到的运行结果如下:
【运行结果示意图】
我认为是如下逻辑导致我没有得到预期的完整结果:

if child not in nodes:
        nodes[child] = Node(child)
    nodes[child].parent = nodes[parent]

我需要所有子节点都能正确展示在树中,例如第三个根节点(00_06_MaxBIS_v2-2.sql)当前仅显示子节点00_07_AnlagenDatenLaden_v1-7.sql,缺失了子节点00_Gebietsstrukturen_v1-2.sql。请问有没有方法可以在树中正确保留重复子节点?要得到预期结果应该使用什么逻辑?


解答

根因分析

anytree框架中每个Node实例仅支持绑定一个父节点。你当前的实现用脚本名作为全局唯一key缓存Node实例,当同一个脚本作为多个父节点的子节点时,后续的父节点赋值操作会直接覆盖原有的父关联,导致之前的父节点下丢失该子节点。

解决方法

不要复用子节点实例,每次遇到新的父子关联都创建独立的子节点实例即可。如果需要后续识别节点对应的脚本,可以给Node新增自定义属性存储脚本名,不需要依赖全局唯一的节点实例缓存。

修正后代码

from anytree import Node, RenderTree

# 仅缓存根节点/父节点实例,避免重复创建同级父节点
parent_node_map = {}
for parent_name in df["parent_script"].unique():
    if parent_name not in parent_node_map:
        parent_node_map[parent_name] = Node(parent_name, script_name=parent_name)

# 遍历所有父子关系,每次创建独立的子节点实例
for _, row in df.iterrows():
    parent_node = parent_node_map[row["parent_script"]]
    # 每次生成新的子节点,不做全局缓存
    Node(row["child_script"], script_name=row["child_script"], parent=parent_node)

# 输出树结构逻辑不变
roots = df[~df["parent_script"].isin(df["child_script"])]["parent_script"].unique()
for root_name in roots:
    for pre, _, node in RenderTree(parent_node_map[root_name]):
        print(f"{pre}{node.name}")

如果后续需要对相同脚本名的节点做批量操作,遍历全树节点通过script_name属性筛选即可。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 15:54:03