将"yield from"语句转换为Python 2.7代码

vka*_*l11 66 python yield generator python-2.x yield-from

我在Python 3.2中有一个代码,我想在Python 2.7中运行它.我确实转换了它(已经把missing_elements两个版本的代码都放了)但我不确定这是否是最有效的方法.基本上如果yield frommissing_element功能的上半部分和下半部分有两个如下所示的调用会发生什么?两个部分(上部和下部)中的条目是否在一个列表中相互附加,以便父级递归函数与yield from调用一起使用并将两个部分一起使用?

def missing_elements(L, start, end):  # Python 3.2
    if end - start <= 1: 
        if L[end] - L[start] > 1:
            yield from range(L[start] + 1, L[end])
        return

index = start + (end - start) // 2

# is the lower half consecutive?
consecutive_low =  L[index] == L[start] + (index - start)
if not consecutive_low:
    yield from missing_elements(L, start, index)

# is the upper part consecutive?
consecutive_high =  L[index] == L[end] - (end - index)
if not consecutive_high:
    yield from missing_elements(L, index, end)

def main():
    L = [10, 11, 13, 14, 15, 16, 17, 18, 20]
    print(list(missing_elements(L, 0, len(L)-1)))
    L = range(10, 21)
    print(list(missing_elements(L, 0, len(L)-1)))

def missing_elements(L, start, end):  # Python 2.7
    return_list = []                
    if end - start <= 1: 
        if L[end] - L[start] > 1:
            return range(L[start] + 1, L[end])

    index = start + (end - start) // 2

    # is the lower half consecutive?
    consecutive_low =  L[index] == L[start] + (index - start)
    if not consecutive_low:
        return_list.append(missing_elements(L, start, index))

    # is the upper part consecutive?
    consecutive_high =  L[index] == L[end] - (end - index)
    if not consecutive_high:
        return_list.append(missing_elements(L, index, end))
    return return_list
Run Code Online (Sandbox Code Playgroud)

aba*_*ert 83

如果您不使用收益率的结果,*您可以随时将其转为:

yield from foo
Run Code Online (Sandbox Code Playgroud)

......进入这个:

for bar in foo:
    yield bar
Run Code Online (Sandbox Code Playgroud)

可能存在性能成本,**但是从来没有语义差异.


来自两半(上部和下部)的条目是否在一个列表中相互附加,以便父递归函数具有来自调用的收益并将两个一起使用?

没有!迭代器和生成器的重点在于您不构建实际列表并将它们附加在一起.

效果是相似的:你只从一个产出,然后从另一个产出.

如果你认为上半部分和下半部分是"懒惰列表",那么是的,你可以把它想象成一个"懒惰的附加",创建一个更大的"懒惰列表".如果你调用list父函数的结果,你当然得到一个实际list的相当于将你可能得到的两个列表附加在一起yield list(…)而不是yield from ….

但我认为反过来更容易想到它:它的作用与for循环完全相同.

如果你将两个迭代器保存到变量中并循环itertools.chain(upper, lower),那就像循环第一个然后循环遍历第二个一样,对吧?这里没什么区别.实际上,您可以实现chain:

for arg in *args:
    yield from arg
Run Code Online (Sandbox Code Playgroud)

*不是生成器对其调用者产生的值,即生成器中的yield表达式本身的值(来自使用该send方法的调用者),如PEP 342中所述.你没有在你的例子中使用这些.而且我愿意打赌你不是真正的代码.但是,协程式代码通常使用yield from表达式的值- 请参阅PEP 3156作为示例.这样的代码通常依赖于Python 3.3生成器的其他功能 - 特别是StopIteration.value来自引入的相同PEP 380的新功能yield from - 所以它必须重写.但如果没有,你可以使用PEP也向你展示完全可怕的杂乱等同物,你当然可以减少你不关心的部分.如果你不使用表达式的值,它会减少到上面的两行.

**不是很大,除了使用Python 3.3或完全重构代码之外,你无能为力.这与将列表推导转换为Python 1.5循环完全相同,或者在版本XY中进行新优化并且您需要使用旧版本时的任何其他情况.

  • 你可能想要产生`bar`,而不是'foo`. (2认同)

Tad*_*sen 7

我只是碰到这个问题,我使用的是一个有点困难,因为我需要返回值yield from

result = yield from other_gen()
Run Code Online (Sandbox Code Playgroud)

这不能表示为一个简单的for循环,但可以用这个重现:

_iter = iter(other_gen())
try:
    while True: #broken by StopIteration
        yield next(_iter)
except StopIteration as e:
    if e.args:
        result = e.args[0]
    else:
        result = None
Run Code Online (Sandbox Code Playgroud)

希望这会帮助遇到同样问题的人。:)


Cli*_*ill 7

如何使用pep-380中的定义来构建 Python 2 语法版本:

该声明:

RESULT = yield from EXPR
Run Code Online (Sandbox Code Playgroud)

在语义上等同于:

_i = iter(EXPR)
try:
    _y = next(_i)
except StopIteration as _e:
    _r = _e.value
else:
    while 1:
        try:
            _s = yield _y
        except GeneratorExit as _e:
            try:
                _m = _i.close
            except AttributeError:
                pass
            else:
                _m()
            raise _e
        except BaseException as _e:
            _x = sys.exc_info()
            try:
                _m = _i.throw
            except AttributeError:
                raise _e
            else:
                try:
                    _y = _m(*_x)
                except StopIteration as _e:
                    _r = _e.value
                    break
        else:
            try:
                if _s is None:
                    _y = next(_i)
                else:
                    _y = _i.send(_s)
            except StopIteration as _e:
                _r = _e.value
                break
RESULT = _r
Run Code Online (Sandbox Code Playgroud)

在生成器中,语句:

return value
Run Code Online (Sandbox Code Playgroud)

在语义上等价于

raise StopIteration(value)
Run Code Online (Sandbox Code Playgroud)

except不同之处在于,目前,返回生成器中的子句无法捕获异常。

StopIteration 异常的行为就像这样定义的:

class StopIteration(Exception):

    def __init__(self, *args):
        if len(args) > 0:
            self.value = args[0]
        else:
            self.value = None
        Exception.__init__(self, *args)
Run Code Online (Sandbox Code Playgroud)


ovg*_*vin 6

用 for 循环替换它们:

yield from range(L[start] + 1, L[end])

==>

for i in range(L[start] + 1, L[end]):
    yield i
Run Code Online (Sandbox Code Playgroud)

元素也一样:

yield from missing_elements(L, index, end)

==>

for el in missing_elements(L, index, end):
    yield el
Run Code Online (Sandbox Code Playgroud)