使用yield进行递归

发布于 2024-12-28 15:14:06 字数 702 浏览 1 评论 0原文

有没有办法混合递归和yield语句?例如,一个无限数生成器(使用递归)将类似于:

def infinity(start):
    yield start
    # recursion here ...

>>> it = infinity(1)
>>> next(it)
1
>>> next(it)
2

我尝试过:

def infinity(start):
    yield start
    infinity(start + 1)

并且

def infinity(start):
    yield start
    yield infinity(start + 1)

但是它们都没有达到我想要的效果,第一个生成器在生成 start 后停止,第二个生成器生成 < code>start,然后是生成器,然后停止。

注意:拜托,我知道你可以使用 while 循环来做到这一点:

def infinity(start):
    while True:
        yield start
        start += 1

我只是想知道这是否可以递归地完成。

Is there any way to mix recursion and the yield statement? For instance, a infinite number generator (using recursion) would be something like:

def infinity(start):
    yield start
    # recursion here ...

>>> it = infinity(1)
>>> next(it)
1
>>> next(it)
2

I tried:

def infinity(start):
    yield start
    infinity(start + 1)

and

def infinity(start):
    yield start
    yield infinity(start + 1)

But none of them did what I want, the first one stopped after it yielded start and the second one yielded start, then the generator and then stopped.

NOTE: Please, I know you can do this using a while-loop:

def infinity(start):
    while True:
        yield start
        start += 1

I just want to know if this can be done recursively.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

薄凉少年不暖心 2025-01-04 15:14:06

是的,您可以这样做:

def infinity(start):
    yield start
    for x in infinity(start + 1):
        yield x

不过,一旦达到最大递归深度,这就会出错。

从 Python 3.3 开始,您将能够使用

def infinity(start):
    yield start
    yield from infinity(start + 1)

If you just recursively call yourgenerator function withoutlooping it or yield from-ing it,你所做的就是构建一个新的生成器,而不需要实际运行函数体或产生任何东西。

有关更多详细信息,请参阅 PEP 380

Yes, you can do this:

def infinity(start):
    yield start
    for x in infinity(start + 1):
        yield x

This will error out once the maximum recursion depth is reached, though.

Starting from Python 3.3, you'll be able to use

def infinity(start):
    yield start
    yield from infinity(start + 1)

If you just call your generator function recursively without looping over it or yield from-ing it, all you do is build a new generator, without actually running the function body or yielding anything.

See PEP 380 for further details.

丢了幸福的猪 2025-01-04 15:14:06

在某些情况下,对于生成器来说,最好使用堆栈而不是递归。应该可以使用堆栈和 while 循环重写递归方法。

下面是一个使用回调并且可以使用堆栈逻辑重写的递归方法的示例:

def traverse_tree(callback):
    # Get the root node from somewhere.
    root = get_root_node()
    def recurse(node):
        callback(node)
        for child in node.get('children', []):
            recurse(child)
    recurse(root)

上面的方法遍历节点树,其中每个节点都有一个可能包含子节点的 children 数组。当遇到每个节点时,会发出回调并将当前节点传递给它。

该方法可以这样使用,打印出每个节点上的一些属性。

def callback(node):
    print(node['id'])
traverse_tree(callback)

使用堆栈代替,并将遍历方法编写为生成器

# A stack-based alternative to the traverse_tree method above.
def iternodes():
    stack = [get_root_node()]
    while stack:
        node = stack.pop()
        yield node
        for child in reversed(node.get('children', [])):
            stack.append(child)

(注意,如果您想要与原来相同的遍历顺序,则需要反转子级的顺序,因为附加到堆栈的第一个子级将是最后一个弹出。)

现在您可以获得与上面的 traverse_tree 相同的行为,但使用生成器:

for node in iternodes():
    print(node['id'])

这不是一个一刀切的解决方案,但对于某些生成器,您可能会得到一个很好的结果替代递归的堆栈处理。

In some cases it might be preferable to use a stack instead of recursion for generators. It should be possible to rewrite a recursive method using a stack and a while loop.

Here's an example of a recursive method which uses a callback and can be rewritten using stack logic:

def traverse_tree(callback):
    # Get the root node from somewhere.
    root = get_root_node()
    def recurse(node):
        callback(node)
        for child in node.get('children', []):
            recurse(child)
    recurse(root)

The above method traverses a node tree where each node has a children array which may contain child nodes. As each node is encountered, the callback is issued and the current node is passed to it.

The method could be used this way, printing out some property on each node.

def callback(node):
    print(node['id'])
traverse_tree(callback)

Use a stack instead and write the traversal method as a generator

# A stack-based alternative to the traverse_tree method above.
def iternodes():
    stack = [get_root_node()]
    while stack:
        node = stack.pop()
        yield node
        for child in reversed(node.get('children', [])):
            stack.append(child)

(Note that if you want the same traversal order as originally, you need to reverse the order of children because the first child appended to the stack will be the last one popped.)

Now you can get the same behavior as traverse_tree above, but with a generator:

for node in iternodes():
    print(node['id'])

This isn't a one-size-fits-all solution but for some generators you might get a nice result substituting stack processing for recursion.

霊感 2025-01-04 15:14:06
def lprint(a):
    if isinstance(a, list):
        for i in a:
            yield from lprint(i)
    else:
        yield a

b = [[1, [2, 3], 4], [5, 6, [7, 8, [9]]]]
for i in lprint(b):
    print(i)
def lprint(a):
    if isinstance(a, list):
        for i in a:
            yield from lprint(i)
    else:
        yield a

b = [[1, [2, 3], 4], [5, 6, [7, 8, [9]]]]
for i in lprint(b):
    print(i)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文