[英]yield/return from python generators
Bumped into a behaviour I'm struggling to grasp without an assistance. 陷入一种我在没有帮助的情况下难以掌握的行为。 Here's a recursive function:
这是一个递归函数:
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
raises StopIteration
which is not handled by caller so exception is raised before anything returns. return value
将引发StopIteration
,调用者无法处理该StopIteration
,因此在返回任何内容之前会引发异常。
If return value
is substituted by yield value; return
如果将
return value
替换为yield value; return
yield value; return
like this: yield 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)
or yield value; raise StopIteration
或
yield value; raise StopIteration
yield value; raise StopIteration
or yield value; raise StopIteration(value)
yield value; raise StopIteration
或yield value; raise StopIteration(value)
yield value; raise StopIteration(value)
or loop is hidden under else
clause then exception is handled by caller the way I expect and function eventually returns '0'
. 在
else
子句下隐藏yield value; raise StopIteration(value)
或循环,然后由调用程序按我期望的方式处理异常,函数最终返回'0'
。 All of these also raise exception: raise StopIteration
, both bare and with argument, yield; return value
所有这些还引发异常:
raise StopIteration
,裸露并带有参数yield; return value
yield; return value
, and bare return
. yield; return value
,并没有return
。
In short, caller breaks when StopIteration
is raised and yield
never returned. 简而言之,调用方在
StopIteration
引发时中断,并且yield
从不返回。
Why? 为什么?
PEP380 states that first StopIteration
is handled in a different way then others. PEP380指出,首先以不同于其他方式的方式处理
StopIteration
。 PEP479 says: PEP479说:
Currently, StopIteration raised accidentally inside a generator function will be interpreted as the end of the iteration by the loop construct driving the generator.
当前,生成器函数内部意外引发的StopIteration将被驱动生成器的循环构造解释为迭代结束。
Apparently, except the first time. 显然,除了第一次。 Still, the details of underlying implementation and exact reasoning behind it are unclear to me.
我仍然不清楚底层实现的细节及其背后的确切原因。
Two more additional questions: 另外两个问题:
what's the right way of writing this snippet? 编写此代码段的正确方法是什么? return (yield value) ?
回报(收益率) ?
is it a quirk, a feature, or something else? 是怪癖,功能还是其他?
Edit: fixed mistakes in code 编辑:修复代码中的错误
Edit2: As far as I understand the execution flow in the first snippet is following: Edit2:据我了解,第一个代码段中的执行流程如下:
countdown
creates generator from recursive('5', ['1', '2', '3'])
countdown
从recursive('5', ['1', '2', '3'])
创建生成器recursive('5', ['1', '2', '3'])
recursive('11', [])
recursive('11', [])
StopIteration('11')
is raised StopIteration('11')
And here is the tricky part. 这是棘手的部分。 What happens here?
这里会发生什么? How
StopIteration
is handled? 如何处理
StopIteration
?
Second snippet: 第二段:
'11'
is yielded upwards until it reaches countdown '11'
向上产生直到达到倒数 if '11' == '0'
if '11' == '0'
被拒绝 yield '11'
and raises StopIteration
yield '11'
并提高StopIteration
'0'
'0'
From what I see now that is pretty much expected behaviour. 从我现在所看到的,这几乎是预期的行为。
StopIteration
is intrecepted by it's caller and does not propagate upward. StopIteration
被其调用者感知,并且不会向上传播。 Caller in turn raises StopIteration
without arguments. 调用者依次引发不带参数的
StopIteration
。 That is why the '11'
part of an original exception never reached countdown
. 这就是为什么原始异常的
'11'
部分从未达到countdown
。 Exception in the first snippet traceback was bare StopIteration
raised in countdown
by recursive('5', ['1', '2', '3']
. 第一个代码段回溯中的异常是
recursive('5', ['1', '2', '3']
在countdown
引发的StopIteration
。
StopIteration
is raised when you finally run out of operands. 当您最终用完操作数时,将引发
StopIteration
。 Until then, you continue to recur on your list, evaluating results and shortening the list. 在此之前,您将继续出现在列表中,评估结果并缩短列表。 I think that the yield has returned, but it returned to its caller, which was the previous invocation of
recursive
, rather than countdown
. 我认为yield已返回,但返回给调用方,这是先前
recursive
,而不是countdown
调用。
In the second example, you yield a value, and the ensuing call to recursive
is what raises StopIteration
, as it immediately hits a return. 在第二个示例中,您产生一个值,随后对
recursive
的调用引起StopIteration
,因为它立即达到了返回值。
As for the example return (yield 42)
, yes, this is a quirk. 至于示例
return (yield 42)
,是的,这是一个怪癖。 The poster of that question was stumbling through making a generator, and discovered that code he later thought was wrong, had actually returned something. 这个问题的发布者在制造发电机时绊脚石,发现他后来认为是错误的代码实际上返回了一些东西。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.