[英]yield/return from python generators
陷入一種我在沒有幫助的情況下難以掌握的行為。 這是一個遞歸函數:
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
,調用者無法處理該StopIteration
,因此在返回任何內容之前會引發異常。
如果將return value
替換為yield value; return
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)
或yield value; raise StopIteration
yield value; raise StopIteration
或yield value; raise StopIteration(value)
在else
子句下隱藏yield value; raise StopIteration(value)
或循環,然后由調用程序按我期望的方式處理異常,函數最終返回'0'
。 所有這些還引發異常: raise StopIteration
,裸露並帶有參數yield; return value
yield; return value
,並沒有return
。
簡而言之,調用方在StopIteration
引發時中斷,並且yield
從不返回。
為什么?
PEP380指出,首先以不同於其他方式的方式處理StopIteration
。 PEP479說:
當前,生成器函數內部意外引發的StopIteration將被驅動生成器的循環構造解釋為迭代結束。
顯然,除了第一次。 我仍然不清楚底層實現的細節及其背后的確切原因。
另外兩個問題:
編寫此代碼段的正確方法是什么? 回報(收益率) ?
是怪癖,功能還是其他?
編輯:修復代碼中的錯誤
Edit2:據我了解,第一個代碼段中的執行流程如下:
countdown
從recursive('5', ['1', '2', '3'])
創建生成器recursive('5', ['1', '2', '3'])
recursive('11', [])
StopIteration('11')
這是棘手的部分。 這里會發生什么? 如何處理StopIteration
?
第二段:
'11'
向上產生直到達到倒數 if '11' == '0'
被拒絕 yield '11'
並提高StopIteration
'0'
從我現在所看到的,這幾乎是預期的行為。 StopIteration
被其調用者感知,並且不會向上傳播。 調用者依次引發不帶參數的StopIteration
。 這就是為什么原始異常的'11'
部分從未達到countdown
。 第一個代碼段回溯中的異常是recursive('5', ['1', '2', '3']
在countdown
引發的StopIteration
。
當您最終用完操作數時,將引發StopIteration
。 在此之前,您將繼續出現在列表中,評估結果並縮短列表。 我認為yield已返回,但返回給調用方,這是先前recursive
,而不是countdown
調用。
在第二個示例中,您產生一個值,隨后對recursive
的調用引起StopIteration
,因為它立即達到了返回值。
至於示例return (yield 42)
,是的,這是一個怪癖。 這個問題的發布者在制造發電機時絆腳石,發現他后來認為是錯誤的代碼實際上返回了一些東西。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.