Python 標準庫 collections 提供了五個極具實用價值的特殊容器類型,本文逐一解析 namedtuple、deque、defaultdict、OrderedDict、Counter 的核心特性、適用場景與最佳實踐。
痛點:(1, 2) 代表座標?還是 RGB 色值?
from collections import namedtuple
# 定義型別
Point = namedtuple('Point', ['x', 'y'])
Circle = namedtuple('Circle', ['x', 'y', 'r'])
# 建立實例
p = Point(1, 2)
c = Circle(0, 0, 10)
# 屬性存取(比索引直觀)
print(p.x, p.y) # 1 2
print(c.r) # 10
# 仍保有 tuple 特性
print(isinstance(p, tuple)) # True
print(p[0]) # 1(索引相容)
print(len(p)) # 2
# _asdict() 轉字典
print(p._asdict()) # {'x': 1, 'y': 2}
# _replace() 產生新實例(不可變)
p2 = p._replace(x=10)
print(p2) # Point(x=10, y=2)
適用場景:資料傳輸物件 (DTO)、資料庫記錄映射、函式多返回值、設定選項群組。
list 在頭部插入/刪除為 O(n);deque 針對兩端優化為 O(1)。
from collections import deque
q = deque(['a', 'b', 'c'])
q.append('x') # 右端加入
q.appendleft('y') # 左端加入
print(q) # deque(['y', 'a', 'b', 'c', 'x'])
q.pop() # 右端彈出 -> 'x'
q.popleft() # 左端彈出 -> 'y'
print(q) # deque(['a', 'b', 'c'])
# 實用參數:maxlen 自動截斷(固定視窗)
recent = deque(maxlen=3)
for i in range(10):
recent.append(i)
print(recent) # deque([7, 8, 9], maxlen=3)
適用場景:BFS 佇列、滑動視窗、最近 N 筆記錄、生產者-消費者緩衝區。
from collections import defaultdict
# 工廠函式:鍵不存在時自動呼叫
dd = defaultdict(lambda: 'N/A')
dd['key1'] = 'abc'
print(dd['key1']) # 'abc'
print(dd['key2']) # 'N/A'(自動建立)
# 常用工廠:list、set、int、dict
# 統計詞頻
from collections import Counter # 見下文
words = ['apple', 'banana', 'apple', 'cherry']
freq = defaultdict(int)
for w in words:
freq[w] += 1
print(dict(freq)) # {'apple': 2, 'banana': 1, 'cherry': 1}
# 分組收集
data = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
grouped = defaultdict(list)
for k, v in data:
grouped[k].append(v)
print(dict(grouped))
# {'yellow': [1, 3], 'blue': [2, 4], 'red': [1]}
關鍵優勢:消除 if key not in dict: dict[key] = [] 等防衛性程式碼。
Python 3.7+ 內建 dict 已保證插入序,但 OrderedDict 仍提供獨特方法:
from collections import OrderedDict
od = OrderedDict()
od['z'] = 1
od['y'] = 2
od['x'] = 3
print(list(od.keys())) # ['z', 'y', 'x'] 依插入序
# move_to_end(key, last=True) 移動鍵至兩端
od.move_to_end('z')
print(list(od.keys())) # ['y', 'x', 'z']
# popitem(last=True) 彈出兩端
od.popitem(last=False) # 彈出最舊 ('y', 2)
# 實作 LRU 快取
class LRUCache(OrderedDict):
def __init__(self, capacity):
super().__init__()
self.capacity = capacity
def get(self, key):
if key not in self:
return -1
self.move_to_end(key) # 標記最近使用
return self[key]
def put(self, key, value):
if key in self:
self.move_to_end(key)
self[key] = value
if len(self) > self.capacity:
self.popitem(last=False) # 淘汰最久未用
from collections import Counter
c = Counter('programming')
print(c)
# Counter({'g': 2, 'm': 2, 'r': 2, 'a': 1, 'i': 1, 'o': 1, 'n': 1, 'p': 1})
# 直接支援算術運算
c1 = Counter(a=3, b=1)
c2 = Counter(a=1, b=2)
print(c1 + c2) # Counter({'a': 4, 'b': 3})
print(c1 - c2) # Counter({'a': 2}) (負值被捨棄)
print(c1 & c2) # 交集 Counter({'a': 1, 'b': 1})
print(c1 | c2) # 聯集 Counter({'a': 3, 'b': 2})
# most_common(n) 前 N 高頻
print(c.most_common(3)) # [('g', 2), ('m', 2), ('r', 2)]
| 需求 | 推薦容器 |
|---|---|
| 固定欄位、不可變、語意化存取 | namedtuple |
| 高頻頭尾插刪、固定視窗、佇列/棧 | deque |
| 缺鍵自動初始化(list/set/int) | defaultdict |
| 需保持順序、LRU、移動鍵位 | OrderedDict |
| 頻率統計、多重集合運算 | Counter |
善用 collections 五大神器,能將大量樣板代碼化為一行,同時獲得更好的效能與可讀性。建議將此模組列為 Python 開發者必背工具箱。