惯用Python:传播产量或扁平化序列?

时间:2010-12-14 21:44:38

标签: python yield tree-traversal

我正在编写广度深度优先树遍历函数,我想要做的是:

def traverse(node):
    yield node
    for n in node.children:
        yield_all traverse(n) # << if Python had a yield_all statement

这个想法是在树中结束一个(平坦的)节点序列。

方法#1 :(传播产量)

def traverse(node):
    yield node
    for n in node.children:
        for m in traverse(n):
            yield m

方法#2 :(展平序列)

def traverse(node):
    return itertools.chain([node],*(traverse(n) for n in node.children))

第一种方法看起来更干净,但我觉得在每个级别的子树中明确yield每个节点都很奇怪。

第二种方法简洁而略显肮脏,但它与我在Haskell中编写的内容相符:

traverse node = node : concatMap traverse (children node)

所以我的问题是:哪个更好?或者我错过了最好的第三选择?

4 个答案:

答案 0 :(得分:4)

[更新] 请参阅PEP-380,此全部语法可从Python 3.3开始作为yield from

def traverse(node):
    yield node
    for n in node.children:
        yield from traverse(n)

答案 1 :(得分:3)

我先去。几次后你就会克服收益率。 : - )

答案 2 :(得分:1)

这是一个意见问题,因此所有答案都只是价值判断。据我所知,没有优雅的第三种方式。

我的观点是第一种方式胜出手。它更清晰,更容易阅读 - 虽然Python可以做一些功能性的东西,但它不是Haskell,而且功能方法通常看起来不那么整洁。

答案 3 :(得分:0)

遍历节点位置:

def iter_tree(t, i=0, j=0):
    yield (i, j), t
    for j, n in enumerate(t.children):
        yield from iter_tree(n, i + 1, j)

for (i, j), n in iter_tree(t):
    print(i*'    ', (i, j), n)