
在第 4 章我們學過了 Python 的基礎四大天王:list, tuple, set, dict。但在處理特定問題時,這些通用容器可能不夠高效或不夠方便。
本章將帶您探索 Python 標準函式庫中的 collections 模組,這裡面藏著許多讓資深開發者愛不釋手的「特種部隊」。
1. Counter:計數神器
統計列表中元素出現的次數是超常見的需求。
傳統寫法 vs Counter
data = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple']
# 傳統寫法
count = {}
for item in data:
if item in count:
count[item] += 1
else:
count[item] = 1
# 結果: {'apple': 3, 'banana': 2, 'orange': 1}
# 使用 Counter
from collections import Counter
c = Counter(data)
print(c)
# 結果: Counter({'apple': 3, 'banana': 2, 'orange': 1})
Counter 不僅寫法簡潔,還提供了強大的方法:
# 取得出現頻率最高的前 n 名
print(c.most_common(2))
# [('apple', 3), ('banana', 2)]
# 兩個 Counter 相加
c1 = Counter(a=3, b=1)
c2 = Counter(a=1, b=2)
print(c1 + c2)
# Counter({'a': 4, 'b': 3})
2. defaultdict:告別 KeyError
使用普通字典 (dict) 時,存取不存在的 key 會噴出 KeyError。我們常需要用 if key in dict 或 dict.get() 來防禦。defaultdict 讓我們能預設一個工廠函數,當 key 不存在時自動產生預設值。
from collections import defaultdict
# 範例:將單字按首字母分組
words = ['apple', 'banana', 'cherry', 'apricot', 'blueberry']
# 設定 default_factory 為 list,不存在的 key 會自動初始化為 []
grouped_words = defaultdict(list)
for word in words:
first_letter = word[0]
grouped_words[first_letter].append(word)
print(dict(grouped_words))
# {'a': ['apple', 'apricot'], 'b': ['banana', 'blueberry'], 'c': ['cherry']}
常見的 factory 對應:
defaultdict(int)→ 預設為 0 (適合計數)defaultdict(list)→ 預設為 [] (適合分組)defaultdict(set)→ 預設為 set() (適合去重分組)
3. deque:雙端佇列 (Double-ended Queue)
普通的 list 在尾端新增 (append) 或刪除 (pop) 很快 (O(1)),但在開頭插入或刪除 (insert(0, ...), pop(0)) 非常慢 (O(n)),因為所有後面的元素都要移動位置。
deque (發音如 “deck”) 專為兩端的高效操作而設計。
from collections import deque
import time
# 比較 deque 與 list 在頭部插入的效能
d = deque()
start = time.time()
for i in range(100000):
d.appendleft(i) # O(1) 操作
print(f"Deque 花費時間: {time.time() - start:.4f} 秒")
l = []
start = time.time()
for i in range(100000):
l.insert(0, i) # O(n) 操作,隨著列表變長會越來越慢
print(f"List 花費時間: {time.time() - start:.4f} 秒")
結論:如果你需要實作 Queue (先進先出) 或 Stack (後進先出),且涉及大量的頭尾操作,請務必使用
deque。
4. namedtuple:具名元組,讓程式碼更可讀
Tuple ((10, 20)) 輕量且不可變,但缺點是存取時只能用索引 (p[0], p[1]),可讀性差。namedtuple 讓我們能給每個欄位取名字,同時保留 tuple 的省記憶體特性。
from collections import namedtuple
# 定義一個 Point 結構
Point = namedtuple('Point', ['x', 'y'])
p = Point(10, 20)
# 使用屬性名稱存取,比 p[0] 清楚多了!
print(f"X座標: {p.x}, Y座標: {p.y}")
# 依然保有 tuple 的特性 (解構、不可變)
x, y = p
print(x, y)
在 Python 3.7+,我們也推薦使用 Dataclasses (下一章會提到),但在簡單的資料容器場景下,namedtuple 依然是不可多得的神器。
5. 總結
掌握 collections 模組是 Python 進階之路的必經之地。
| 資料結構 | 適用情境 | 相比基礎型別優勢 |
|---|---|---|
| Counter | 統計元素頻率 | 比手寫 for loop 簡潔且快 |
| defaultdict | 分組、計數、嵌套字典 | 避免 KeyError,省去初始化檢查 |
| deque | 佇列 (Queue/Stack) | 頭尾操作效能遠勝 list |
| namedtuple | 簡單的資料物件 | 比 tuple 具可讀性,比 class 省記憶體 |
下一章,我們將探討 Python 中最迷人的特性之一:迭代器 (Iterators) 與生成器 (Generators),學會如何處理無限大的數據流!
延伸閱讀: