如何在Python anytree中定位特定后代节点,不存在时返回None?
Anytree路径式访问子节点(不存在返回None)
场景说明
先通过以下代码构建树结构:
from anytree import Node, RenderTree, AsciiStyle top = Node("top") a = Node("a", parent=top) b = Node("b", parent=top) c = Node("c", parent=a) d = Node("d", parent=a) e1 = Node("e", parent=c) e2 = Node("e", parent=a) c1 = Node("c", parent=b) e3 = Node("e", parent=c1) print(RenderTree(top, style=AsciiStyle()).by_attr())
执行后生成树结构:
top |-- a | |-- c | | +-- e | |-- d | +-- e +-- b +-- c +-- e
当前通过字符串匹配查找节点的实现:
import anytree gnode = anytree.search.find(top, lambda node : str(node)=="Node('/top/a/c/e')") print(f"Exp match, rcv {gnode}") gnode = anytree.search.find(top, lambda node : str(node)=="Node('/top/a/c/f')") print(f"Exp None, rcv {gnode}")
执行结果:
Exp match, rcv Node('/top/a/c/e') Exp None, rcv None
需求:希望用类似top.get_descendant("a/c/e")的直接路径访问方式获取节点,不存在时返回None,替代当前的字符串匹配查找方案。
解决方案
方案1:使用内置Resolver类
Anytree提供了Resolver工具,可通过路径字符串定位节点,配合异常处理返回None:
from anytree import Resolver # 基于节点name属性匹配路径 resolver = Resolver('name') # 查找存在的节点 try: target_node = resolver.get(top, "a/c/e") except ValueError: target_node = None print(target_node) # 输出 Node('/top/a/c/e') # 查找不存在的节点 try: target_node = resolver.get(top, "a/c/f") except ValueError: target_node = None print(target_node) # 输出 None
方案2:封装成工具函数或自定义节点方法
如果想要更简洁的调用方式,可以封装成工具函数:
from anytree import Resolver resolver = Resolver('name') def get_descendant(node, path): try: return resolver.get(node, path) except ValueError: return None # 使用示例 print(get_descendant(top, "a/c/e")) # Node('/top/a/c/e') print(get_descendant(top, "a/c/f")) # None
也可以通过猴子补丁给Node类添加方法,实现top.get_descendant()的调用形式:
from anytree import Node, Resolver resolver = Resolver('name') def get_descendant(self, path): try: return resolver.get(self, path) except ValueError: return None Node.get_descendant = get_descendant # 直接调用 print(top.get_descendant("a/c/e")) # Node('/top/a/c/e') print(top.get_descendant("a/c/f")) # None
方案3:手动逐层遍历路径
如果不想依赖Resolver,可以手动分割路径并逐层查找子节点:
def get_descendant(node, path): current_node = node for segment in path.split('/'): # 查找当前节点下匹配名称的子节点 current_node = next((child for child in current_node.children if child.name == segment), None) if current_node is None: break return current_node # 使用示例 print(get_descendant(top, "a/c/e")) # Node('/top/a/c/e') print(get_descendant(top, "a/c/f")) # None
内容的提问来源于stack exchange,提问作者Craig
相关产品推荐
相关产品推荐

