解决暂停(序列化)和恢复递归生成器堆栈的变通方法?

时间:2013-11-02 18:42:13

标签: python recursion tree generator python-3.3

我有一个递归生成器函数,它创建一个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对于这里的递归是必要的(编辑:至少没有一些繁琐的堆栈管理),所以我认为它需要是一个生成器,不是吗?有解决方法吗?

2 个答案:

答案 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分段运行它。这一切都在课堂上,当然还有更多的内容,但这是它的主旨。