Python 内置的列表、字典、集合、元组已经足够好用,但在特定场景下,有些高频操作用它们实现会显得啰嗦或不够高效。collections 模块就是为解决这些“差一点”的需求而生的——它提供了一组高级容器类型,让常用操作写起来更优雅、运行也更高效。
namedtuple:有名字的元组
元组的缺点是只能通过索引访问元素,代码可读性差。namedtuple 解决了这个问题,它创建一个元组的子类,每个位置都有对应的字段名,既能像元组一样轻量、不可变,又能通过名字访问。
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(10, 20)
print(p.x, p.y) # 10 20
print(p[0]) # 10,依然支持索引
使用场景:表示简单的数据记录,比如坐标、数据库查询结果、配置文件条目。既比类轻量(没有实例字典),又比普通元组可读。还可以用 _replace 方法创建部分修改的新对象。
deque:双端队列
列表在头部插入或删除元素时,所有后续元素都要移动,时间复杂度 O(n)。deque(double-ended queue)是双向队列,从两端添加或弹出元素都极快(O(1)),也支持自动限制长度。
from collections import deque
dq = deque(['a', 'b', 'c'], maxlen=4)
dq.appendleft('start')
dq.append('end')
print(dq) # deque(['start', 'a', 'b', 'c', 'end'], maxlen=4) 实际超过maxlen会把另一端的元素挤掉
使用场景:实现队列或栈,保存最近的 n 条记录(如日志缓存),广度优先搜索的节点队列。maxlen 特性尤其适合做“历史记录”功能。
defaultdict:带默认值的字典
访问字典中不存在的键会抛出 KeyError,常规做法是用 dict.get() 或者先判断 if key in d。defaultdict 则可以在键缺失时自动生成一个默认值,省去判断步骤。
from collections import defaultdict
# 按单词首字母分组
words = ['apple', 'banana', 'cat', 'ant']
by_letter = defaultdict(list) # 默认值是空列表
for w in words:
by_letter[w[0]].append(w)
print(by_letter) # defaultdict(<class 'list'>, {'a': ['apple', 'ant'], 'b': ['banana'], 'c': ['cat']})
使用场景:分组统计、计数器嵌套、构建邻接表。接收的默认工厂可以是 list、set、int,也可以自定义函数。特别适合简化代码中大量“如果不存在就初始化”的逻辑。
OrderedDict:有序字典
Python 3.7 起普通字典也保证了插入顺序,但 OrderedDict 额外提供了几个专有方法,比如把某键移到末尾或开头、按插入顺序倒序迭代。
from collections import OrderedDict
od = OrderedDict()
od['a'] = 1
od['b'] = 2
od['c'] = 3
od.move_to_end('a') # 把'a'移到末尾
print(list(od.keys())) # ['b', 'c', 'a']
使用场景:实现 LRU 缓存、按添加顺序输出配置项、需要控制顺序变动的场景。虽然普通字典有序了,但 OrderedDict 的排序操作和相等比较(考虑顺序)依然有独特价值。
Counter:计数器
统计元素出现次数是日常任务,用普通字典要写一堆 if。Counter 直接完成,并提供了数学集合操作。
from collections import Counter
text = "the quick brown fox jumps over the lazy dog"
word_counts = Counter(text.split())
print(word_counts.most_common(3)) # [('the', 2), ('over', 1), ('quick', 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}) # 只保留正数计数
使用场景:词频统计、用户投票统计、分析日志中的事件分布。most_common 直接取 TopN,加减运算可以合并多个计数结果。
ChainMap:链式映射
当需要在多个字典中查找一个键时,ChainMap 把它们串联成一个逻辑视图,按传入顺序搜索,修改只影响第一个映射。
from collections import ChainMap
defaults = {'theme': 'light', 'lang': 'en'}
user_settings = {'lang': 'zh'}
combined = ChainMap(user_settings, defaults)
print(combined['theme']) # light ,来自defaults
print(combined['lang']) # zh ,来自user_settings,优先找到
combined['theme'] = 'dark' # 修改只会影响第一个映射 user_settings
print(user_settings) # {'lang': 'zh', 'theme': 'dark'}
print(defaults) # {'theme': 'light', 'lang': 'en'} 未改变
使用场景:配置管理,按优先级合并默认配置、环境变量、用户传入参数。相比用 update 复制合并,ChainMap 节省内存且保持原始字典独立。
总结:collections 模块的容器是对内置类型的精准补充,它们解决的都是真实编码中的“小痛点”。记住它们的存在,当你下次想用字典做默认值判断、想用列表实现队列却发现性能问题时,就知道该搬出哪个工具了。