迭代器與生成器是 Python 中處理數據流、實現惰性計算的核心機制。它們不僅統一了容器訪問接口,更能以極低的內存開銷處理海量甚至無限數據流。本文從概念、協議、實現到進階應用,為你全景式拆解這對「黃金搭檔」。
迭代器是實現迭代器協議的對象,僅需定義兩個方法:
__iter__():返回迭代器對象本身__next__() (Python 3) / next() (Python 2):返回下一個元素,耗盡時拋出 StopIteration>>> i = iter('abc')
>>> next(i)
'a'
>>> next(i)
'b'
>>> next(i)
'c'
>>> next(i)
Traceback (most recent call last):
...
StopIteration
class Countdown:
def __init__(self, start):
self.current = start
def __iter__(self):
return self
def __next__(self):
if self.current < 0:
raise StopIteration
val = self.current
self.current -= 1
return val
for n in Countdown(3):
print(n) # 3, 2, 1, 0
__iter__ 的對象均可用 for 循環遍歷,無論底層是列表、集合、文件還是數據庫游標。生成器是創建迭代器的「語法糖」,核心關鍵字是 yield。包含 yield 的函數調用時不會立即執行,而是返回一個生成器對象。
def fibonacci():
a, b = 0, 1
while True:
yield b
a, b = b, a + b
fib = fibonacci()
print(next(fib)) # 1
print(next(fib)) # 1
print([next(fib) for _ in range(10)]) # [2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233]
類似列表推導式,將方括號改為圓括號即可:
>>> squares = (x * x for x in range(10))
>>>> squares
at 0x...>
>>>> for n in squares:
... print(n)
0, 1, 4, 9, 16, 25, 36, 49, 64, 81
yield 不僅能「產出」值,還能通過 send() 接收外部傳入的值,實現雙向數據流,這是協程的基礎:
def psychologist():
print('請說出你的煩惱')
while True:
answer = (yield) # 接收 send() 傳入的值
if answer is not None:
if answer.endswith('?'):
print("別問自己太多問題")
elif 'good' in answer:
print("很好,繼續說")
elif 'bad' in answer:
print("別太消極")
free = psychologist()
next(free) # 啟動生成器,輸出「請說出你的煩惱」
free.send('我感覺很糟') # 輸出「別太消極」
free.send("為什麼我不該這樣?") # 輸出「別問自己太多問題」
free.send("好吧,我要找點好事") # 輸出「很好,繼續說」
此處 yield 暫停函數執行並保存上下文(局部變量、指令指針),下次 next() 或 send() 時從暫停處恢復,這正是「微線程」協程的運行模型。
多個生成器可串聯形成數據處理管道,代碼清晰且內存高效:
def power(values):
for v in values:
print(f'powering {v}')
yield v
def adder(values):
for v in values:
print(f'adding to {v}')
yield v + 3 if v % 2 == 0 else v + 2
elements = [1, 4, 7, 9, 12, 19]
res = adder(power(elements)) # 管道組合
print(next(res)) # powering 1 -> adding to 1 -> 3
print(next(res)) # powering 4 -> adding to 4 -> 7
這種「拉取式」流處理模式,是大數據框架(如 Spark RDD、Flink DataStream)的核心思想縮影。
| 場景 | 推薦方案 | 理由 |
|---|---|---|
| 簡單序列轉換/過濾 | 生成器表達式 | 語法簡潔,一行搞定 |
| 複雜狀態邏輯/無限序列 | 生成器函數 | 可維護局部狀態,邏輯清晰 |
| 需重複遍歷/隨機訪問 | 列表/元組 | 生成器只能一次性消費 |
| 自定義容器類型 | 實現 __iter__/__next__ 類 | 完全控制迭代行為 |
| 雙向通信/狀態機 | 基於 yield 的協程 | 天然支持暫停/恢復/傳值 |
掌握迭代器與生成器,意味著你擁有了處理數據流的「瑞士軍刀」——無論是解析超大 JSON、流式處理視頻幀,還是構建異步任務調度器,都能以優雅、高效、Pythonic 的方式落地。