Python itertools 練習指南:惰性資料流
itertools 是一組小型迭代器工具。它們不試圖解決整個問題,而是可以組合。認識 count、islice、chain 和 groupby 之後,很多迴圈會變得更短、更容易讀。
給無限流加上邊界
count 會永遠產生值,只有另一個函式限制請求數量時才有用。islice 截取前綴,而不把整個流變成列表。結果仍然是惰性的,需要查看時再包起來。
from itertools import count, islice
print(list(islice(count(10), 3)))有限的視窗
用 chain 拼接資料流
chain 按順序讀取輸入,不會排序或去重。它可以直接替代「把一個列表追加到另一個列表」的迴圈。輸入很大時,chain 不必預先建構合併後的列表。
from itertools import chain
print(list(chain([1, 2], ["a", "b"])))兩個流合成一個
只分組相鄰的鍵
groupby 在鍵變化時開始新組,不會搜尋整個輸入中的相同鍵。相同值不相鄰時,先按同一個鍵排序再分組。前進到下一組之前,要消費完目前分組。
from itertools import groupby
data = [("a", 1), ("a", 2), ("b", 3)]
for key, group in groupby(data, key=lambda pair: pair[0]):
print(key, list(group))連續分組
先排序再分組
分組鍵和排序鍵必須一致。穩定排序會保留相同鍵內部的原始順序,這通常正是想要的結果。排序後,groupby 才能把相同鍵看成一個連續片段。
from itertools import groupby
data = [("b", 1), ("a", 2), ("a", 3)]
sorted_data = sorted(data, key=lambda pair: pair[0])
print([(key, len(list(group))) for key, group in groupby(sorted_data, key=lambda pair: pair[0])])先排序,再分組
有意識地物化
大多數 itertools 結果是迭代器,只能消費一次,也不支援下下標存取。需要列印、計數或多輪走訪時,再轉換成列表。物化應發生在邊界,而不是每個階段中間。
from itertools import chain
result = list(chain([1], [2, 3]))
print(result)
print(result[1])在邊界轉成列表
你的練習清單
- 用 islice 給 count 或其他無限迭代器加邊界。
- 用 chain 拼接可迭代物件,避免追加迴圈。
- groupby 之前按同一個鍵排序。
- 前進到下一組前先消費目前分組。
- 只有需要下標或復用時才轉成列表。
常見問題
groupby 會排序資料嗎?
不會。它只分組相鄰元素。相同鍵可能分散時,先按同一個鍵排序。
chain 可以拼接字串嗎?
可以。它會像 for 迴圈一樣,逐個字元走訪每個字串。
為什麼 itertools 結果是空的?
很可能迭代器已經被消費。迭代器只能使用一次;建立新的迭代器,或者先物化成列表。
練習 itertools
12 道題,覆蓋 count、islice、chain、groupby 和惰性迭代器行為。
繼續閱讀: