我有一个递归生成器函数,它创建一个ChainMap上下文树,最后用树末端的上下文做一些事情。它看起来像这样(parent_context
是一个ChainMap,hierarchy
是一个列表):
def recursive_generator(parent_context, hierarchy):
next_level = hierarchy[0]
next_level_contexts = get_contexts(next_level) # returns a list of dicts
for context in next_level_contexts:
child_context = parent_context.new_child().update(context)
if next_level == hierarchy[-1]:
yield do_something(**child_context)
else:
yield from recursive_generator(child_context, hierarchy[1:])
现在,我想标记层次结构的一个级别,以便在完成该级别后操作暂停,将状态序列化为磁盘,以便稍后从中断处获取。有没有办法在不失去递归的优雅的情况下做到这一点?
我知道你不能pickle生成器,所以我想重构为迭代器对象。但我认为yield from
对于这里的递归是必要的(编辑:至少没有一些繁琐的堆栈管理),所以我认为它需要是一个生成器,不是吗?有解决方法吗?
答案 0 :(得分:2)
你似乎正在用DFS探索一棵树。所以你可以在内存中构造树并使DFS显式化。然后只存储树并重新启动最左边的节点(我想?)。
这实际上是“繁琐的堆栈管理”,但它有一个很好的图片,可以帮助实现它(至少对我来说,看看你的问题,因为树的DFS使得实现看起来相当明显 - 在我想到之前)就这样,它似乎很复杂 - 但我可能会遗漏一些东西。)
对不起,如果这显而易见且不够......
[编辑]
class Inner:
def __init__(self, context, hierarchy):
self.children = []
next_level = hierarchy[0]
next_level_contexts = get_contexts(next_level)
for context in next_level_contexts:
child_context = parent_context.new_child().update(context)
if next_level == hierarchy[-1]:
self.children.append(Leaf(context))
else:
self.children.append(Inner(child_context, hierarchy[1:]))
def do_something(self):
# this will do something on the left-most leaf
self.children[0].so_something()
def prune(self):
# this will remove the left-most leaf
if isinstance(self.children[0], Leaf):
self.children.pop(0)
else:
self.children[0].prune()
if not self.children[0]:
self.children.pop(0)
def __bool__(self):
return bool(self.children)
class Leaf:
def __init__(self, context):
self.context = context
def do_something():
do_something(**self.context)
上面的代码尚未经过测试。我最终使用节点类,因为元组似乎太混乱了。您可以通过创建父节点来创建树。那么你可以通过调用do_something
“做某事”,之后你会想要用prune
删除“完成”叶子:
tree = Inner(initial_context, initial_hierarchy)
while tree:
tree.do_something()
tree.prune()
我很确定它会包含错误,但希望它足以显示这个想法。对不起,我不能做更多,但我需要重新种植植物......
你可以用生成器编写代码,但不知道DFS是什么,这很有趣。你可能会喜欢阅读“算法设计手册” - 这是教科书的一部分和部分参考资料,它不会像对待白痴一样对待你(我也没有正式的计算机科学教育,我认为这是一本好书)。 / p>[编辑改为最左边,这是你以前的,我认为]
和alko有一个好点...
答案 1 :(得分:1)
这是我最终做的事情:
def recursive_generator(parent_context, hierarchy):
next_level = hierarchy[0]
next_level_contexts = get_contexts(next_level) # returns a list of dicts
for context in next_level_contexts:
child_context = parent_context.new_child().update(context)
if next_level == hierarchy[-1]:
yield child_context
else:
yield from recursive_generator(child_context, hierarchy[1:])
def traverse_tree(hierarchy):
return list(recursive_generator(ChainMap(), hierarchy)
def do_things(contexts, start, stop):
for context in contexts[start:stop]:
yield do_something(**context)
然后我可以挑选traverse_tree
返回的列表,然后加载它并使用do_things
分段运行它。这一切都在课堂上,当然还有更多的内容,但这是它的主旨。