人人都会AI编程

8.5 高级容器:collections 模块

更新时间:2026-07-12

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:带默认值的字典

普通字典访问不存在的键会抛出 KeyErrordefaultdict 允许你指定一个工厂函数,当访问缺少的键时,自动调用该函数生成默认值并存入字典。

用法示例

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:计数器

Counterdict 的一个子类,专门用于统计可哈希元素的出现次数。可以理解为“多重集”,提供了一系列便于计数的操作。

用法示例

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 只是引用了原字典,而不是拷贝,所以原字典的修改会即时反映到链中。


这六种高级容器各有擅长,掌握它们能让你的代码既简洁又专业。需要时查一下官方文档,很快就能上手。