Как отмечает mgibsonbr, поскольку вы храните родительский указатель, это можно сделать итеративно, отслеживая только текущий узел (и его отступ):
def print_tree(from_path):
node, indent = model.get_iter(from_path), 0
while node:
if indent: # don't print the root
print "-" * indent, node.columns[0]
if node.children: # walk to first child before walking to next sibling
node = node.children[0]
indent += 1
elif node.next: # no children, walk to next sibling if there is one
node = node.next
else:
# no children, no more siblings: find closet ancestor w/ more siblings
# (note that this might not be the current node's immediate parent)
while node and not node.next:
node = node.parent
indent -= 1
node = node and node.next
Вы можете превратить это в генератор, заменив строку print
на yield indent, node
.
Мне пришлось смоделировать некоторые тестовые данные, чтобы отладить это. Вот что у меня есть, на случай, если кто-то еще захочет поиграть. Я рассматривал корень как неспособный иметь братьев и сестер (нет причин, по которым он не может иметь next
и хранить данные в columns
, но тогда вы захотите, чтобы ваши отступы начинались с 1).
class Node(object):
def __init__(self, parent=None, sib=None, value=""):
self.parent = parent
self.prev = sib
self.next = None
self.children = []
self.columns = [str(value)]
def child(self, value):
child = Node(self, None, value)
if self.children:
self.children[-1].next = child
child.prev = self.children[-1]
self.children.append(child)
return child
def sib(self, value):
return self.parent.child(value)
class model(object):
@staticmethod
def get_iter(_):
root = Node()
root.child("0").child("0:0").child("0:0:0").sib("0:0:1") \
.child("0:0:1:0").sib("0:0:1:0").parent.sib("0:0:2")
root.children[0].child("0:1").parent.sib("1")
return root