'来自'在Python 2中替代

时间:2017-11-16 12:14:29

标签: python python-2.7 generator yield-from

我的代码在 递归调用 中的python3中使用yield from,它完全正常。现在的问题是,这是 PEP-380中{/ 3>}引入的,我需要它在python 3.3中工作。我读了几篇文章,其中没有一篇文章足够简单或足够简单。

很少有人提到文章:

和其他几个人。

我已经重新创建了一个小样本代码(它采用多级列表并返回一个展平列表) 非常简约 与我的要求相比。

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

#driver values:

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

由于python 2.7无法使用,转换后的内容在yield from中无效。

2 个答案:

答案 0 :(得分: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().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]
PEP 380 -- Syntax for Delegating to a Subgenerator(而不是PEP 342)中引入了{p> yield from,特别是因为子生成器上的循环不会委托generator.throw()generator.send()信息。

PEP明确指出:

  

如果值的产生是唯一的问题,那么使用诸如

之类的循环可以毫不费力地执行
for v in g:
    yield v

Formal Semantics有一个Python实现等效,起初可能看起来令人生畏,但您仍然可以选择循环(使用while 1:,循环结束时有处理例外或StopIteration,使用next()generator.send(..)检索新值,并生成结果(使用yield _y)。

答案 1 :(得分: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]