Python yield生成器詳解

2020-07-16 10:05:26
使用了 yield 語句的函數稱為生成器(generator)。與普通函數不同的是,生成器是一個返回疊代器的函數,只能用於迭代操作,因此生成器實際上是一種特殊的疊代器。呼叫一個生成器函數,返回的是一個疊代器物件。

使用 yield 語句相當於為函數封裝好 __iter__() 和 __next__() 方法。在呼叫生成器執行的過程中,每次遇到 yield 語句時函數會暫停並儲存函數執行的狀態,返回 yield 語句中表示式的值,並在下一次執行 next( ) 方法時從當前位置繼續執行。

yield 可以理解為“return”,返回其後表示式的值給呼叫者。不同的是 return 返回後,函數會釋放,而生成器則不會。在直接呼叫 next 方法或用 for 語句進行下一次疊代時,生成器會從 yield 下一句開始執行,直至遇到下一個 yield。

以下程式碼使用帶 yield 語句的生成器得到斐波那契數列:
import sys
def Fibonacci(n):
    a, b, counter = 0, 1, 0
    while True:
        if(counter > n):
            return
        yield a
        a, b = b, a + b
        counter += 1

f = Fibonacci(15)
    while True:
    try:
        print(next(f), end=" ")
    except StopIteration:
        sys.exit()
上述程式碼的執行結果如下所示:

>>> import sys
>>> def Fibonacci(n):
...          a, b, counter = 0, 1, 0
...          while True:
...              if(counter > n):
...                  return
...              yield a
...              a, b = b, a + b
...              counter += 1

>>> while True:
...     try:
...         print(next(f), end=" ")
...     except StopIteration:
...         sys.exit()
       
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 


不帶 yield 語句的生成器可以用來定義生成器表示式,將列表轉換為元組。使用生成器表示式取代列表推導式可以同時節省 CPU 和記憶體資源。例如:
L = [1, 2, 3, 4, 5]
T = tuple(i for i in L)
print(T)
上述程式碼的執行結果如下所示:

>>> L = [1, 2, 3, 4, 5]
>>> T = tuple(i for i in L)
>>> print(T)
(1, 2, 3, 4, 5)


一些 Python 內建函數可以識別這是生成器表示式,直接代入運算,例如:
print(sum(i for i in range(100)))
上述程式碼的執行結果如下所示:

>>> print(sum(i for i in range(100)))
4950


注意,根據左開右閉原則,上述程式碼中的 range(100) 得到的列表是從 0 到 99,不包括 100。