1

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

几篇参考文章:

和其他几个。

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

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

#驱动程序值:

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

python 2.7由于yield from. _

4

2 回答 2

3

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

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

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()or .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 fromPEP 380 --委托给子生成器的语法(不是 PEP 342)中引入,特别是因为子生成器上的循环不会委托generator.throw()generator.send()信息。

PEP 明确指出:

如果产生值是唯一需要考虑的问题,则可以使用循环来轻松执行此操作,例如

for v in g:
    yield v

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

于 2017-11-16T12:19:59.377 回答
1

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

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]
于 2017-11-16T12:19:59.797 回答