【问题标题】:'yield from' substitute in Python 2Python 2 中的“yield from”替代品
【发布时间】:2018-04-29 23:27:45
【问题描述】:

我的代码在递归调用中使用python3 中的yield from,它工作得非常好。现在的问题是,这是 PEP-380python 3.3 中引入的,我需要它在python 2.7 中工作。我阅读了几篇文章,但没有一篇足够详细或足够简单。

几篇被引用的文章:

还有其他几个。

我重新创建了一个小的示例代码(它接受一个多级列表并返回一个扁平列表),它非常简约与我的要求相比。

#python 3
def foo(obj):
    for ele in obj:
        if isinstance(ele, list):
            yield from foo(ele)
        else:
            yield ele

#driver 值:

>>> l = [1, [2, 3, [4,5]]]
>>> list(foo(l))
=>  [1, 2, 3, 4, 5]

由于yield from 不可用,相同的转换在python 2.7 中不起作用。

【问题讨论】:

  • 为什么一定要递归?在内部yield from 也只是一个循环。
  • 然而,yield from 的核心是一个带有委托的循环。您不需要委托,但您仍需要循环
  • 好的。愚蠢的我。有用。那里的答案有点混乱,我无法理解。让我换个问题。
  • 请注意,yield from 未在 PEP 342 中引入。PEP 380 处理 yield from
  • @MartijnPieters:注意到

标签: python python-2.7 generator yield-from


【解决方案1】:

仍需要循环。你在这里有递归并不重要。

您需要遍历递归调用产生的生成器并产生结果:

def foo(obj):
    for ele in obj:
        if isinstance(ele, list):
            for res in foo(ele):
                yield res
        else:
            yield ele

您的递归调用会生成一个生成器,您需要将生成器的结果向前传递。为此,您可以循环生成器并生成各个值。

没有更好的选择,除了升级到 Python 3。

yield from 本质上将循环的责任传递给调用者,并将任何generator.send()generator.throw() 调用传递回委托的生成器。你不需要传递.send().throw(),剩下的就是自己负责循环。

演示:

>>> import sys
>>> sys.version_info
sys.version_info(major=2, minor=7, micro=14, releaselevel='final', serial=0)
>>> def foo(obj):
...     for ele in obj:
...         if isinstance(ele, list):
...             for res in foo(ele):
...                 yield res
...         else:
...             yield ele
...
>>> l = [1, [2, 3, [4,5]]]
>>> list(foo(l))
[1, 2, 3, 4, 5]

yield from 是在 PEP 380 -- Syntax for Delegating to a Subgenerator(不是 PEP 342)中引入的,特别是因为子生成器上的循环不会委托 generator.throw()generator.send() 信息。

PEP 明确指出:

如果产生值是唯一需要考虑的问题,则可以使用诸如

之类的循环轻松执行此操作
for v in g:
    yield v

Formal Semantics 有一个 Python 实现等价物,一开始可能看起来很吓人,但你仍然可以发现它循环while 1:,当出现异常时循环结束或@处理 987654335@,使用 next()generator.send(..) 检索新值,并生成结果(使用 yield _y)。

【讨论】:

  • 不错的答案。照常。 ;)
【解决方案2】:

为什么说“我的代码不能使用循环,需要递归”?您可以轻松地在递归生成器中使用循环:

def foo(obj):
    for ele in obj:
        if isinstance(ele, list):
            #yield from foo(ele)
            for t in foo(ele):
                yield t 
        else:
            yield ele

l = [1, [2, 3, [4, 5]]]
print list(foo(l))

输出

[1, 2, 3, 4, 5]

【讨论】:

    猜你喜欢
    • 2021-09-30
    • 2020-05-09
    • 2014-01-10
    • 2016-06-01
    • 2023-01-25
    • 2021-04-26
    • 2013-07-09
    • 2014-11-16
    • 2020-12-31
    相关资源
    最近更新 更多