字典叶生成器

Dictionary leaf generator

这是我的树,一个嵌套的字典

tree = {"root": {"branch_a": {"branch_aa": 0, "branch_ab": 1},
                 "branch_b": 1,
                 "branch_c": {"branch_ca": {"branch_caa": 0}}}}

我设法编写了一个打印所有叶子的函数

def print_leaves(tree):
    if not hasattr(tree, "__iter__"):
        print(tree)
    elif isinstance(tree, dict):
        for branch in tree.values():
            print_leaves(branch)

产生所需的输出

0
1
1
0

在这一点上,我认为将操作(在本例中为打印)与对叶子的访问分离会很好。所以我稍微修改了上面的函数,把它变成了一个生成器,并将打印部分移动到一个for循环中。

def generate_leaves(tree):
    if not hasattr(tree, "__iter__"):
        yield tree
    elif isinstance(tree, dict):
        for branch in tree.values():
            generate_leaves(branch)

for leaf in generate_leaves(tree):
    print(leaf)

...不幸的是,这不起作用。

首先,为什么它不起作用? 然后,当然,如何正确编写叶生成器?

您没有使用递归调用的结果。这适用于没有 return 值的 print_leaves,但不适用于具有 returnyield.

的函数

这里是长版:

def generate_leaves(tree):
    if not hasattr(tree, "__iter__"):
        yield tree
    elif isinstance(tree, dict):
        for branch in tree.values():
            for leaf in generate_leaves(branch):
                yield leaf

for leaf in generate_leaves(tree):
    print(leaf)

幸运的是,我们可以使用 yield from:

来缩短很多
def generate_leaves(tree):
    if not hasattr(tree, "__iter__"):
        yield tree
    elif isinstance(tree, dict):
        for branch in tree.values():
            yield from generate_leaves(branch)

for leaf in generate_leaves(tree):
    print(leaf)

请注意,您只需要 if / else 满足一个条件;不需要具有两个冗余条件的 if / elif

def generate_leaves(tree):
    if not isinstance(tree, dict):
        yield tree
    else:
        for branch in tree.values():
            yield from generate_leaves(branch)

for leaf in generate_leaves(tree):
    print(leaf)

关于 yield from 的资源:

  • PEP-0380;
  • In practice, what are the main uses for the new "yield from" syntax in Python 3.3?