簡體   English   中英

python生成器的收益/回報

[英]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 StopIterationyield 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:據我了解,第一個代碼段中的執行流程如下:

  1. countdownrecursive('5', ['1', '2', '3'])創建生成器recursive('5', ['1', '2', '3'])
  2. 生成器一直沿樹生成recursive('11', [])
  3. 此時,將引發StopIteration('11')

這是棘手的部分。 這里會發生什么? 如何處理StopIteration

第二段:

  1. 相同
  2. 相同
  3. '11'向上產生直到達到倒數
  4. if '11' == '0'被拒絕
  5. 控制流返回到yield '11'並提高StopIteration
  6. 重復直到'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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM