Python 内置的列表、字典、集合已经很强,但 collections 模块提供了几个更专业的容器类型,能在特定场景下让代码更简洁、更高效。下面逐一介绍最常用的几个。
namedtuple:有名字的元组
普通元组通过索引访问元素,t[0]、t[1] 不够直观,可读性差。namedtuple 给每个位置赋予一个字段名,既能像元组一样轻量,又能像对象一样通过 .属性 访问。
用法示例:
from collections import namedtuple
# 定义一个“点”类型,包含 x 和 y 两个字段
Point = namedtuple('Point', ['x', 'y'])
p = Point(10, 20)
print(p.x, p.y) # 10 20
print(p[0], p[1]) # 同样支持索引访问,10 20
实用场景:
- 替代简单的数据类(比如存储坐标、RGB 颜色、数据库查询结果行)。
- 让函数返回多个值时更有可读性,而不是返回一个普通元组。
注意:namedtuple 是不可变的,和普通元组一样,创建后不能修改字段值。如果需要修改,可以用 _replace() 方法生成一个新实例。
deque:高效双端队列
列表在尾部插入或删除很快(O(1)),但在头部操作就很慢(O(n)),因为所有元素都要移位。deque(双端队列)在两端都可以高效地添加和删除(O(1)),并且可以指定最大长度。
用法示例:
from collections import deque
q = deque(['a', 'b', 'c'])
q.append('d') # 右边进
q.appendleft('z') # 左边进
print(q) # deque(['z', 'a', 'b', 'c', 'd'])
q.pop() # 右边出
q.popleft() # 左边出
实用场景:
- 实现队列或栈(比列表更高效)。
- 保存最近 N 条历史记录:
deque(maxlen=100),当元素超过 100 时,另一端的元素会自动丢弃,很适合日志缓存、滑动窗口。
defaultdict:带默认值的字典
普通字典访问不存在的键会抛出 KeyError。defaultdict 允许你指定一个工厂函数,当访问缺少的键时,自动调用该函数生成默认值并存入字典。
用法示例:
from collections import defaultdict
# 用 int 做工厂,默认值为 0(int() 返回 0)
word_count = defaultdict(int)
words = ['apple', 'banana', 'apple']
for w in words:
word_count[w] += 1 # 不需要判断 w 是否存在
print(dict(word_count)) # {'apple': 2, 'banana': 1}
# 用 list 做工厂,默认值为空列表
groups = defaultdict(list)
groups['fruits'].append('apple')
groups['fruits'].append('banana')
groups['vegetables'].append('carrot')
常用工厂函数:
int→ 默认 0(计数)list→ 默认[](分组)set→ 默认set()(去重分组)- 自定义函数:
lambda: 'hello'
注意:defaultdict 在访问不存在键时会创建并插入该键值对,如果只是临时查询不想写入,还是得用普通字典或 dict.get()。
OrderedDict:保持顺序的字典
从 Python 3.7 开始,内置的 dict 已经保证插入顺序,所以大多数场景下 OrderedDict 不再是必需。但它还有几个特殊的额外功能,在某些场景依然有用:
- 相等比较时考虑顺序:两个内容相同但插入顺序不同的
OrderedDict是不相等的,而普通dict在 Python 3.7+ 中比较时会忽略顺序差异。 - 提供移动元素到开头/结尾的方法:
popitem(last=True)和move_to_end(key)等,可以实现 LRU 缓存之类功能。
用法示例:
from collections import OrderedDict
od = OrderedDict()
od['a'] = 1
od['b'] = 2
od['c'] = 3
# 移动到末尾
od.move_to_end('a')
print(list(od.keys())) # ['b', 'c', 'a']
# 移到开头
od.move_to_end('b', last=False)
print(list(od.keys())) # ['b', 'c', 'a']
除非你用到上述特殊方法,否则直接用内置 dict 即可。
Counter:计数器
Counter 是 dict 的一个子类,专门用于统计可哈希元素的出现次数。可以理解为“多重集”,提供了一系列便于计数的操作。
用法示例:
from collections import Counter
cnt = Counter('abracadabra')
print(cnt) # Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1})
# 取出现最多的 3 个
print(cnt.most_common(3)) # [('a', 5), ('b', 2), ('r', 2)]
# 数学操作:两个计数器
cnt1 = Counter(a=3, b=1)
cnt2 = Counter(a=1, b=2)
print(cnt1 + cnt2) # 相加:Counter({'a': 4, 'b': 3})
print(cnt1 - cnt2) # 相减(结果忽略负数):Counter({'a': 2})
print(cnt1 & cnt2) # 交集:取最小值:Counter({'a': 1, 'b': 1})
print(cnt1 | cnt2) # 并集:取最大值:Counter({'a': 3, 'b': 2})
实用场景:
- 统计单词频率、字符频率。
- 数据集中各类别分布。
- 快速找出众数。
ChainMap:链式映射
ChainMap 把多个字典或映射对象串联起来,形成一个逻辑上的单一映射。查找时按顺序在每个字典中依次搜索,第一个命中的键值生效。写入和删除只会影响第一个字典。
用法示例:
from collections import ChainMap
defaults = {'color': 'red', 'user': 'guest'}
cli_args = {'user': 'admin'}
env = {'size': 'large'}
# 优先级:命令行参数 > 环境变量 > 默认配置
config = ChainMap(cli_args, env, defaults)
print(config['user']) # 'admin' (来自 cli_args)
print(config['color']) # 'red' (来自 defaults)
print(config['size']) # 'large' (来自 env)
# 修改:只影响第一个字典
config['user'] = 'alice'
print(cli_args) # {'user': 'alice'}
实用场景:
- 配置分层管理(命令行 > 文件配置 > 默认值)。
- 作用域模拟(局部作用域 > 外部作用域 > 全局作用域)。
注意:ChainMap 只是引用了原字典,而不是拷贝,所以原字典的修改会即时反映到链中。
这六种高级容器各有擅长,掌握它们能让你的代码既简洁又专业。需要时查一下官方文档,很快就能上手。