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

新手上路,请多包涵

我在 Python 3.2 中有下面的代码,我想在 Python 2.7 中运行它。我确实转换了它(在两个版本中都放入了 missing_elements 的代码)但我不确定这是否是最有效的方法。基本上,如果有两个 yield from 上半部分和下半部分 missing_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

原文由 vkaul11 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 498
2 个回答

如果你不使用你的收益结果,*你 总是 可以把这个:

 yield from foo

……进入这个:

 for bar in foo:
    yield bar

可能会有性能成本,**但从来没有语义差异。


两个部分(上部和下部)的条目是否在一个列表中相互附加,以便父递归函数与 yield from 调用一起使用两个部分?

不!迭代器和生成器的全部要点是您不需要构建实际列表并将它们附加在一起。

效果 是相似的:你只是从一个中屈服,然后从另一个中屈服。

如果您将上半部分和下半部分视为“惰性列表”,那么是的,您可以将其视为创建更大“惰性列表”的“惰性追加”。如果你在父函数的结果上调用 list ,你当然 得到一个实际的 list 这相当于将两个列表附加在一起,如果你已经完成 yield list(…) 而不是 yield from …

但我认为反过来想更容易:它所做的与 for 循环所做的完全相同。

如果将两个迭代器保存到变量中,并循环遍历 itertools.chain(upper, lower) ,这与循环第一个然后循环第二个是一样的,对吗?这里没有区别。事实上,您可以将 chain 实现为:

 for arg in *args:
    yield from arg


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

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

原文由 abarnert 发布,翻译遵循 CC BY-SA 4.0 许可协议

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

该声明:

 RESULT = yield from EXPR

在语义上等同于:

 _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

在生成器中,语句:

 return value

在语义上等同于

raise StopIteration(value)

除了目前,返回生成器中的 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)

原文由 Cliff Hill 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题