惯用Python:传播yield还是扁平化序列?

5 投票
4 回答
2269 浏览
提问于 2025-04-16 08:32

我正在写一个深度优先遍历树的函数,我想要实现的是这个:

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

我的目标是得到树中节点的一个(扁平化的)序列。

方法一:(传播生成)

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

方法二:(扁平化序列)

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

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

第二种方法简洁但稍微有点乱,不过它和我在Haskell中写的代码很像:

traverse node = node : concatMap traverse (children node)

所以我的问题是:哪种方法更好?或者我是不是漏掉了更好的第三种选择?

4 个回答

1

这个问题是个意见类的问题,所以所有的回答都是个人看法。就我所想,似乎没有什么优雅的第三种选择。

我个人认为第一种方法绝对是最好的。它更清晰,也更容易阅读——Python 不是 Haskell,虽然它可以做一些函数式编程的事情,但通常函数式的方法看起来就是不那么整洁。

3

我建议选择第一个。你过几次就会习惯传递收益了。:-)

5

[更新] 请查看 PEP-380,这个 yield all 语法从 Python 3.3 开始可以使用,写法是 yield from:

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

撰写回答