Python进阶:collections模块实战指南
1. 为什么需要collections模块Python内置了list、tuple、dict、set等基础数据结构它们能解决大部分问题。但在实际开发中我们经常会遇到一些特殊场景需要给字典设置默认值避免KeyError想要统计元素出现频率需要记住字典键的插入顺序希望元组的元素可以通过属性访问需要高效的双端队列操作这些场景如果用基础数据结构实现代码会变得冗长且低效。collections模块就是为了解决这些问题而生的它提供了5个特别有用的数据结构工具类from collections import namedtuple, Counter, defaultdict, OrderedDict, deque我刚开始学Python时也好奇为什么这些工具不直接内置到基础类型中后来在真实项目中踩过几次坑才明白保持核心语言的简洁性很重要而collections模块就像是一个瑞士军刀扩展包需要时随时取用。2. namedtuple带字段名的元组2.1 基本用法假设我们要处理二维坐标点用普通元组表示p (1, 2)一个月后看这段代码你能记得p[0]是x坐标还是y坐标吗namedtuple完美解决了这个问题from collections import namedtuple # 创建一个Point类 Point namedtuple(Point, [x, y]) p Point(1, 2) print(p.x) # 1 print(p.y) # 2我特别喜欢用namedtuple替代简单的类定义比如配置项、数据库记录等。它比普通类更节省内存因为继承自tuple同时保持了代码可读性。2.2 高级技巧类型提示支持from typing import NamedTuple class Point(NamedTuple): x: float y: float默认参数Python 3.7Point namedtuple(Point, [x, y], defaults[0, 0]) p Point() # Point(x0, y0)转换字典d {x: 3, y: 4} p Point(**d)实际案例我在处理GPS轨迹数据时用namedtuple表示坐标点代码既简洁又易读TrackPoint namedtuple(TrackPoint, [latitude, longitude, timestamp]) points [TrackPoint(39.9, 116.4, 2023-01-01 08:00)]3. Counter专业的计数器3.1 统计元素频率统计单词出现次数不用Counter的写法words [apple, banana, apple, orange] count {} for word in words: if word not in count: count[word] 0 count[word] 1用Counter只需一行from collections import Counter count Counter(words) # Counter({apple: 2, banana: 1, orange: 1})3.2 实用方法获取前N个常见元素count.most_common(2) # [(apple, 2), (banana, 1)]数学运算c1 Counter(a3, b1) c2 Counter(a1, b2) c1 c2 # Counter({a: 4, b: 3}) c1 - c2 # Counter({a: 2})真实案例分析Nginx日志时我用Counter统计状态码分布status_counts Counter(line.split()[8] for line in open(access.log)) print(status_counts.most_common())4. defaultdict智能字典4.1 避免KeyError普通字典在访问不存在的键时会报错defaultdict则返回默认值from collections import defaultdict # 默认值为0 d defaultdict(int) print(d[a]) # 0 # 默认值为空列表 d defaultdict(list) print(d[key]) # []4.2 分组数据将学生按班级分组students [ (class1, Alice), (class2, Bob), (class1, Charlie) ] classes defaultdict(list) for class_name, student in students: classes[class_name].append(student)我在处理数据库查询结果时经常用这个模式比手动检查键是否存在要优雅得多。5. deque高性能双端队列5.1 基本操作from collections import deque d deque([b, c]) d.append(d) # 右侧添加 d.appendleft(a) # 左侧添加 d.pop() # 右侧删除 d.popleft() # 左侧删除5.2 实际应用实现滑动窗口def sliding_window(items, size): window deque(maxlensize) for item in items: window.append(item) if len(window) size: yield list(window)维护最近记录固定长度recent_items deque(maxlen10) for new_item in data_stream: recent_items.append(new_item)我在实现消息队列消费者时deque的性能比list高出一个数量级特别是在处理大量数据时。6. OrderedDict记住插入顺序的字典6.1 保持顺序虽然Python 3.7的普通dict也保持插入顺序但OrderedDict提供了额外功能from collections import OrderedDict d OrderedDict() d[a] 1 d[b] 2 d[c] 3 print(list(d.keys())) # [a, b, c]6.2 特殊方法移动键到两端d.move_to_end(a) # 移到末尾 d.move_to_end(c, lastFalse) # 移到开头实现LRU缓存class LRUCache: def __init__(self, capacity): self.cache OrderedDict() self.capacity capacity def get(self, key): if key not in self.cache: return -1 self.cache.move_to_end(key) return self.cache[key] def put(self, key, value): if key in self.cache: self.cache.move_to_end(key) self.cache[key] value if len(self.cache) self.capacity: self.cache.popitem(lastFalse)我在实现API缓存层时就用到了这个模式代码简洁且高效。