4

我有一个递归生成器函数,它创建一个 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:])

现在我想标记层次结构的一个级别,以便操作在完成该级别后暂停,将状态序列化到磁盘以便稍后在它停止的地方拾取。有没有办法在不失去递归优雅的情况下做到这一点?

我知道你不能腌制生成器,所以我考虑重构为一个迭代器对象。但我认为yield from这里的递归是必要的(编辑:至少没有一些繁琐的堆栈管理),所以我认为它需要是一个生成器,不是吗?有解决方法吗?

4

2 回答 2

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()

我很确定它会包含错误,但希望它足以展示这个想法。对不起,我不能做更多,但我需要重新种植植物....

ps 很有趣,您可以使用生成器编写代码,但不知道 DFS 是什么。你可能会喜欢阅读“算法设计手册”——它既是教科书,也是参考书,它不会把你当作白痴(我也没有受过正规的计算机科学教育,我认为这是一本好书)。

[编辑到最左边的第一个,我想这是你以前的]

和alko有一个好点...

于 2013-11-03T00:46:07.970 回答
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. 当然,这一切都在一个课程中,还有很多事情要做,但这就是它的要点。

于 2013-11-03T19:42:28.507 回答