第 31 課 · 進階 · 19 分鐘

Python collections

選擇正確的容器,而不是每次手寫同樣的邏輯。

collectionsCounterdefaultdictdeque

Maya 想知道最好賣的飲料、正在排隊的訂單,還有按杯型統計的數量。三個迴圈也能做,三個容器做得更清楚。哪個容器不用 dict.get 就能計數?

collections 模組為常見任務提供專用容器:計數、按鍵分組,以及在兩端添加或刪除元素。它們各自只解決一個小問題,卻能讓程式碼意圖更清楚。 你還會保留固定長度的視窗、疊加設定,並比較庫存。

用 Counter 計數

Counter 是字典的子類,用來統計出現次數。存取不存在的鍵會回傳零,而不是拋出 KeyError。most_common 會把次數最高的項排在前面,適合做匯總和排行。

from collections import Counter

votes = ["tea", "coffee", "tea"]
counts = Counter(votes)
print(counts["tea"])
print(counts.most_common(1))

先計數,再排序

用 defaultdict 分組

存取不存在的鍵時,defaultdict 會呼叫工廠函式。把 list 作為工廠,每個新鍵都會從空列表開始。這樣就不必在追加前反覆檢查鍵是否存在。

from collections import defaultdict

groups = defaultdict(list)
for name, team in [("Ada", "A"), ("Grace", "B"), ("Lin", "A")]:
    groups[team].append(name)

print(dict(groups))

每個新鍵都有一個列表

用 deque 操作兩端

deque 支援在兩端高效添加和刪除。popleft 從隊首移除最早的元素,append 從隊尾加入。它很適合佇列和滑動視窗。

from collections import deque

queue = deque(["a", "b"])
queue.append("c")
queue.popleft()
print(list(queue))

雙端佇列

保留固定長度的滾動視窗

帶 maxlen 的 deque 會自動丟掉最舊的元素,很適合移動平均或短活動流:不用切片複製,也不用維護索引。視窗大小在建立 deque 時就固定下來。

from collections import deque

window = deque(maxlen=3)
for reading in [10, 12, 11, 15]:
    window.append(reading)
    print(list(window), round(sum(window) / len(window), 1))

新值進來,舊值自動離開

用 ChainMap 疊加設定

ChainMap 從左到右尋找各個映射。把使用者設定放前面、預設值放後面,使用者沒有設定的鍵會自動落到預設層,不需要複製合併整本字典。new_child() 可以為一個請求或一個頁面建立臨時覆蓋層。

from collections import ChainMap

defaults = {"theme": "light", "page_size": 20}
user = {"theme": "dark"}
settings = ChainMap(user, defaults)
print(settings["theme"], settings["page_size"])
print("page_size" in user)
scoped = settings.new_child({"page_size": 50})
print(scoped["page_size"], settings["page_size"])

不複製字典也能覆蓋

Counter 運算只保留正庫存

兩個 Counter 相減時,零和負數會被丟掉。用來算剩餘庫存很方便,但結果不再是完整帳本。交集 & 對每個鍵保留較小的計數,回答的是另一個問題:兩份庫存有多少共同部分?

from collections import Counter

stock = Counter({"tea": 3, "latte": 2})
sold = Counter({"tea": 2, "latte": 2, "mocha": 1})
left = stock - sold
print(left)
print(list(left.elements()))
print(stock & sold)

剩餘庫存和共同庫存不是一回事

本課要點

  • Counter 統計可雜湊值,缺失鍵回傳零。
  • most_common 按次數從高到低排序。
  • defaultdict 會為缺失鍵建立預設值。
  • deque 支援高效的兩端操作。
  • 離開局部程式碼時,可以把專用容器轉換成普通列表或字典。
  • 滾動視窗用 maxlen,設定優先級用 ChainMap,庫存視圖用 Counter 運算。

常見錯誤

  • 鍵可能不存在時,仍然對普通字典使用 counts[key]。
  • 忘記 defaultdict 在讀取時也會插入鍵。
  • 需要佇列時反覆使用 list.pop(0),而沒有考慮 deque。
  • 把 Counter 相減當成完整審計記錄:零和負數結果會消失。
輪到你

用 Counter 統計 ['a', 'b', 'a'],再往 defaultdict(list) 裡添加一個新團隊。

動手試試

改改變數、先預測輸出,再執行程式碼。第一次點擊「執行程式碼」時會下載 Python 執行時,可能需要幾秒鐘。

瀏覽器內 Python本機執行 · 無需帳號
首次執行會從 CDN 下載 Pyodide。修改後點擊「執行程式碼」。

練習本課

12 道題,作答後立即看到解釋。

查看 12 道題答案開始練習
← itertoolsfunctools →