如何在 Python 中使用生成器(yield 語句)

了解如何用 Python 編寫生成器。了解yield關鍵字、惰性求值、記憶體優化,並將生成器與清單結構進行比較。

在編輯器中嘗試此解決方案

概述

當處理大量資料集、日誌檔案或無限資料流時,同時將所有元素載入到記憶體中(例如返回一個大列表)很容易耗盡系統 RAM 並使應用程式崩潰。 Python 提供了一個出色的、節省記憶體的解決方案:生成器。

生成器是一種特殊類型的函數,它會傳回惰性迭代器。生成器不是一次計算所有值並傳回它們,而是根據請求逐一產生值。主要區別在於“yield”聲明。當生成器函數呼叫“yield”時,它會暫停其執行狀態(變數、指令指標)並傳回產生的值。當請求下一個值時,該函數將從暫停處準確恢復。

由於生成器計算是延遲執行的,因此無論資料集大小如何,它們都使用幾乎為零的記憶體。 Python 也支援生成器表達式,它使用括號語法「(x for x in data)」來建立輕量級內嵌產生器,而無需宣告完整函數。

程式碼和執行輸出

此腳本示範了使用生成器函數以及yield 語句和生成器表達式來產生序列。

generators_demo.py
在編輯器中嘗試
# 1. Generator function using yield
def count_up_to(limit):
    count = 1
    while count <= limit:
        yield count
        count += 1

# Instantiating the generator
counter = count_up_to(3)
print("Memory safe generator instantiated.")

# Fetching values manually
print("Next 1:", next(counter))
print("Next 2:", next(counter))
print("Next 3:", next(counter))

# 2. Iterating with a for loop (automatically handles StopIteration)
print("\n--- Looping over generator ---")
for num in count_up_to(4):
    print("Num:", num)

# 3. Generator expression (Shorthand syntax)
squares_gen = (x**2 for x in range(1, 4))
print("\nGenerator expression elements:")
print(list(squares_gen)) # Cast to list to print all elements
端子輸出
Memory safe generator instantiated.
Next 1: 1
Next 2: 2
Next 3: 3

--- Looping over generator ---
Num: 1
Num: 2
Num: 3
Num: 4

Generator expression elements:
[1, 4, 9]

逐步實施

  • 使用標準 def 關鍵字定義函數。
  • 使用yield 關鍵字而不是return 將yield 值傳回迭代器流。
  • 使用 for 迴圈迭代產生器或呼叫內建的 next(gen) 函數來提取值。
  • 使用生成器表達式(使用括號)進行簡單的內聯惰性轉換。

常見問題解答

與清單相比,生成器的主要優點是什麼?

記憶體效率。清單同時將所有元素儲存在 RAM 中,而生成器則根據需要逐一產生項目,從而允許您處理大於系統總記憶體的資料集。

當生成器用完物品時會發生什麼事?

Python 引發 StopIteration 異常。 for 循環會自動捕獲此異常以正常退出循環,但在耗盡的生成器上手動呼叫 next() 將引發異常。

相關主題

推薦的 Python 資源

透過相關的互動式教學、備忘單和程式碼比較來擴展您的知識。