收益如何在递归生成器中进行有序遍历?

时间:2019-05-27 10:47:01

标签: python-3.x yield

我正在学习递归生成器,并在网上找到了该程序。

我理解了顺序遍历的递归版本,但是在理解递归生成器时遇到了困难。

特别是我听不懂

  1. 为什么要在for循环中写入“ yield x”?
  2. 为什么'yield x'不在最终列表中?

我试图调试生成器并添加了手表,但是我发现递归调用执行了多次'yield x',并且未将其收集到最终结果中。

class Tree:
    def __init__(self, label, left=None, right=None):
        self.label = label
        self.left = left
        self.right = right

    def __repr__(self, level=0, indent="    "):
        s = level*indent + repr(self.label)
        if self.left:
            s = s + "\\n" + self.left.__repr__(level+1, indent)
        if self.right:
            s = s + "\\n" + self.right.__repr__(level+1, indent)
        return s

    def __iter__(self):
        return inorder(self)


def tree(list):
    n = len(list)
    if n == 0:
        return []
    i = n // 2
    return Tree(list[i], tree(list[:i]), tree(list[i + 1:]))


# Recursive Normal
def inorder(t):
    if t:
        inorder(t.left)
        print(t.label)
        inorder(t.right)


# Recursive Generator
def inorder(t):
    if t:
        for x in inorder(t.left):
            yield x
        yield t.label
        for x in inorder(t.right):
            yield x

t = tree("ABCDEFG")

#  Tree will be like following
#                D
#           /         \
#          B            F
#       /    \       /    \
#      A      C     E       G
#     / \    / \   / \     /  \
#    0  0   0  0  0  0    0    0

# generating in order traversal
print([i for i in inorder(t)])

收益率x在for循环中的作用。

2 个答案:

答案 0 :(得分:0)

不确定您要查找的是什么,但是也许是符合以下几点的事情:

class Tree:
    def __init__(self, label, left=None, right=None):
        self.label = label
        self.left = left
        self.right = right

    def __repr__(self, level=0, indent="    "):
        s = level*indent + repr(self.label)
        if self.left:
            s = s + "\n" + self.left.__repr__(level+1, indent)
        if self.right:
            s = s + "\n" + self.right.__repr__(level+1, indent)
        return s

    def __iter__(self):
        return inorder(self)


def tree(list):
    n = len(list)
    if n == 0:
        return []
    i = n // 2
    return Tree(list[i], tree(list[:i]), tree(list[i + 1:]))


def inorder(t):
    if t:
        for x in t.left:
            yield x
        yield t.label
        for x in t.right:
            yield x

t = tree("ABCDEFG")
[print(i.label) for i in t]

输出:

A
B
C
D
E
F
G

使用该代码,您可以改为:

[print('----------\n', i) for i in t]

将从A到G输出树中的每个分层节点。

编辑:如果您询问Generator的工作方式,也许这个例子可能会启发您:

>>> def list2gen(lst):
...     for elem in lst:
...             yield str(elem) + '_'
...
>>> print(list2gen([1,2,'7',-4]))
<generator object list2gen at 0x000001B0DEF8B0C0>
>>> print(list(list2gen([1,2,'7',-4])))
['1_', '2_', '7_', '-4_']

如果调试器多次中断,但是这些元素从未在生成的生成器中实现,则必须将其归因于调试器中的错误。我使用Python已有十多年了;他们曾经臭虫泛滥。在Python中,范例是“测试为王”和“避免手动调试”,但是我不同意这一点。 (我没有的唯一原因是缺少 Great IDE和调试器。)

答案 1 :(得分:0)

也许您不了解发电机是如何工作的?生成器不同于迭代器,它不是直接计算有价值的集合,而是动态获取所有值。如果inorder(t.left)的结果未被for循环遍历,则yield inorder(t.left)将返回为t.left创建的整个生成器。因为您的整个inorder函数都是生成器。

很遗憾,我无法找到特定的描述文档。这是基于我的经验的描述。欢迎其他人更正我的意见。如果有人可以提供具体的官方说明,欢迎添加