yield from 關鍵字的 return 語句

華科雲商小雪發表於2024-02-06

我經常需要寫一些比較複雜的程式碼,常常會遇到各種各樣的問題。比如我在使用 yield from 表示式時, return 語句的問題。我們知道,在使用 yield from 表示式時, return 語句的作用是在子生成器(被呼叫的生成器)執行完畢後,返回最終的結果到呼叫者。這可以讓生成器在巢狀結構中更清晰地傳遞值。具體情況我會一一用文字記錄下來,方便後期參考:

1、問題背景

使用 "yield from" 表示式時,return 語句的作用是什麼?我在很多示例中都沒有找到 return 語句從 yield from 表示式返回的值。我嘗試了以下簡單的程式碼,但沒有成功:


def 
return4():

    return 4


def yield_from():
    res = yield from range( 4)
    res = yield from return4()


def test_yield_from():
    for x in yield_from():
        print( x)


test_yield_from()

執行該程式碼會產生以下輸出:

» python test.py 0 1 2 3 Traceback (most recent call last):  File "test.py", line 52, in <module>    test_yield_from()  File "test.py", line 48, in test_yield_from    for x in yield_from():  File "test.py", line 44, in yield_from    res = yield from return4() TypeError: 'int' object is not iterable

但我希望的輸出是:

» python test.py 0 1 2 3 4

因為 PEP 中有這樣一段說明:

此外,當迭代器是另一個生成器時,子生成器被允許執行帶有值的 return 語句,該值變為 yield from 表示式的值。

很顯然,我沒有得到這種解釋。在 "yield from" 語句中,子生成器中的 return 語句是如何工作的?

2、解決方案

答案1: 生成器在耗盡時可以返回一個值:


def 
my_gen():

    yield 0
    return "done"

g = my_gen()
next( g)
next( g) # raises StopIteration: "done"

在 yield from 語句中返回的值將是此值。例如:


def 
yield_from():

    res = yield from my_gen()
    assert res == "done"

預設情況下,此值為 None。即 res = yield from range(4) 會將 res 設定為 None。

答案2:

yield from generator 的簡寫為:


for 
i 
in 
generator:

    yield i

好吧,它比這複雜一點: https://www.python.org/dev/peps/pep-0380/#formal-semantics 。如果 generator = 4,則它將無法正常工作。(你的 return4() 不是一個生成器,而是一個函式。)為了得到你想要的結果,你可以這樣做:


def 
yield_from():

    yield from range( 4)
    yield 4

答案3:

我為你提供了測試的一個工作示例。return4 函式現在是一個生成器。為實現這一目標,必須在函式中任何地方出現 yield(Python 3.5 中有一個新的相關特性,但現在並不重要)。

正如你已經引用的:

此外,當迭代器是另一個生成器時,子生成器被允許執行帶有值的 return 語句,該值變為 yield from 表示式的值。

總結:你將得到一個值。例如,你可以列印它:


def 
yield_from():

    # ...
    val = yield from return4()
    print( "value:", val)   # prints value: 4

但你希望的是 yield 它,而不是列印它。以下是完整的程式碼:


def 
return4():

    if False:
        yield None
    return 4

def yield_from():
    yield from range( 4)
    yield ( yield from return4())

def test_yield_from():
    for x in yield_from():
        print( x)

test_yield_from()
# prints numbers 0 to 4

你可能會問自己,它有什麼好處。當你只從生成器接收值時,幾乎沒有任何優勢。但當你向生成器傳送值時,yield from 是一個很棒的特性。嘗試找到有關 Python 協程的良好解釋。它很棒。

其實上面的問題我們知道,具體來說,當一個生成器函式中使用 yield from 呼叫另一個生成器時, return 語句的返回值會成為呼叫者獲取的值。這就允許子生成器產生的值直接傳遞給呼叫者,而不需要在父生成器中一個一個地使用 yield 語句傳遞。所以後期有啥不懂的都可以評論區留言。


來自 “ ITPUB部落格 ” ,連結:https://blog.itpub.net/70034537/viewspace-3006418/,如需轉載,請註明出處,否則將追究法律責任。

相關文章