从python生成器生成/返回

时间:2018-04-17 16:31:17

标签: python yield

陷入了一种我在没有帮助的情况下努力抓住的行为。这是一个递归函数:

OPERATORS = ['+', '-', '*', '/']

def recursive(value, operands):
    if not operands:
        return value
    for operator in OPERATORS:
        new_value = str(eval(value + operator + operands[-1]))
        new_operands = operands[:-1]
        yield from recursive(new_value, new_operands)

def countdown(value, operands):
    return next(i for i in recursive(value, operands) if i == '0')

ans = countdown('5', ['1', '2', '3'])
print(ans)

return value引发调用者未处理的StopIteration,因此在返回任何内容之前会引发异常。

如果return valueyield value; return替换为:

def recursive(value, operands):
    if not operands:
        yield value
        return
    for operator in OPERATORS:
        new_value = str(eval(value + operator + operands[-1]))
        new_operands = operands[:-1]
        yield from recursive(new_value, new_operands)

yield value; raise StopIterationyield value; raise StopIteration(value)或循环隐藏在else子句下,然后异常由调用者以我期望的方式处理,函数最终返回'0'。所有这些都会引发异常:raise StopIteration,无论是裸的还是带参数的,yield; return value和裸return

简而言之,在StopIteration被提升且yield从未返回时,来电者会中断。

为什么?

PEP380声明第一个StopIteration的处理方式与其他方式不同。 PEP479说:

  

目前,在生成器函数内意外引发的StopIteration将被解释为循环结构驱动生成器的迭代结束。

显然,除了第一次。但是,我不清楚底层实施的细节和背后的确切推理。

还有两个问题:

  • 编写此代码段的正确方法是什么? return (yield value)

  • 是怪癖,特征还是别的什么?

修改:修复了代码中的错误

Edit2:据我所知,第一个代码段中的执行流程如下:

  1. countdownrecursive('5', ['1', '2', '3'])
  2. 创建生成器
  3. 将生成器从树中生成到recursive('11', [])
  4. 此时StopIteration('11')被提出
  5. 这是棘手的部分。这里发生了什么?如何处理StopIteration

    第二个片段:

    1. 相同
    2. 相同
    3. '11'向上屈服,直至倒计时
    4. if '11' == '0'
    5. 拒绝的地方
    6. 控制流程返回yield '11'并提升StopIteration
    7. 重复直至'0'
    8. 从我现在看到的,这是非常期待的行为。 StopIteration被其调用者拦截,不会向上传播。呼叫者反过来引发StopIteration而没有参数。这就是原始异常的'11'部分永远不会达到countdown的原因。 StopIteration countdown recursive('5', ['1', '2', '3']引发了第一个代码段回溯中的异常InternalXmlHelper.vb

1 个答案:

答案 0 :(得分:0)

当你最终用完操作数时,会引发

StopIteration。在此之前,您将继续重复列表,评估结果并缩短列表。我认为收益已经返回,但它返回到调用者,这是之前调用的recursive,而不是countdown

在第二个示例中,您会产生一个值,随后调用recursive会引发StopIteration,因为它会立即返回。

至于示例return (yield 42),是的,这是一个怪癖。这个问题的海报是制作发电机的绊脚石,并发现他后来认为错误的代码实际上已经归还了一些东西。