一、collections模块概述
collections 是 Python 标准库中提供增强版容器数据类型的模块。它扩展了内置的 list、tuple、dict、set 等基础容器,提供了更强大、更便捷的数据结构,帮助开发者解决特定场景下的数据存储和处理需求。
from collections import Counter, defaultdict, deque, namedtuple, OrderedDict
# 示例:Counter 统计频率
words = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple']
counter = Counter(words)
print(counter) # Counter({'apple': 3, 'banana': 2, 'orange': 1})
二、namedtuple——带字段名的元组
2.1 基本用法
namedtuple 创建了一个轻量级、不可变的数据类,它像元组一样高效,但可以通过字段名访问元素,提高代码可读性。
from collections import namedtuple
# 定义 namedtuple 类型
Point = namedtuple('Point', ['x', 'y'])
# 或使用字符串:namedtuple('Point', 'x y')
# 创建实例
p1 = Point(10, 20)
p2 = Point(x=30, y=40)
print(p1.x, p1.y) # 10 20(属性访问)
print(p1[0], p1[1]) # 10 20(索引访问)
print(p1) # Point(x=10, y=20)
2.2 特性
from collections import namedtuple
Person = namedtuple('Person', ['name', 'age', 'city'])
# 创建
p = Person('张三', 25, '北京')
# 解包
name, age, city = p
# 替换字段(返回新实例)
p_new = p._replace(age=26)
# 转为字典
print(p._asdict()) # {'name': '张三', 'age': 25, 'city': '北京'}
# 获取字段名
print(p._fields) # ('name', 'age', 'city')
2.3 适用场景
# 实战:处理 CSV 数据
from collections import namedtuple
import csv
withopen('users.csv', 'r') as f:
reader = csv.reader(f)
headers = next(reader)
User = namedtuple('User', headers)
for row in reader:
user = User(*row)
print(f"{user.name} - {user.email}")
三、deque——双端队列
3.1 基本用法
deque(double-ended queue,双端队列)是一个线程安全的队列,支持从两端快速添加和弹出元素,性能优于 list 的头部操作。
from collections import deque
# 创建
dq = deque([1, 2, 3])
print(dq) # deque([1, 2, 3])
# 从右边添加
dq.append(4) # [1, 2, 3, 4]
dq.appendleft(0) # [0, 1, 2, 3, 4]
# 从右边弹出
dq.pop() # 返回 4,deque([0, 1, 2, 3])
dq.popleft() # 返回 0,deque([1, 2, 3])
# 扩展
dq.extend([4, 5]) # [1, 2, 3, 4, 5]
dq.extendleft([0]) # [0, 1, 2, 3, 4, 5]
3.2 限制长度
from collections import deque
# 固定长度,超出自动移除另一端
dq = deque(maxlen=3)
dq.extend([1, 2, 3])
print(dq) # deque([1, 2, 3], maxlen=3)
dq.append(4)
print(dq) # deque([2, 3, 4], maxlen=3) # 1 被移除
3.3 常用方法
from collections import deque
dq = deque([1, 2, 3, 2, 1])
# 旋转
dq.rotate(1) # 右旋转1步: [1, 1, 2, 3, 2]
dq.rotate(-1) # 左旋转1步: [2, 3, 2, 1, 1]
# 计数
print(dq.count(2)) # 2
# 清空
dq.clear()
# 反转
dq = deque([1, 2, 3])
dq.reverse()
print(dq) # deque([3, 2, 1])
3.4 适用场景
# 实战:实现简单队列
from collections import deque
task_queue = deque()
task_queue.append('任务1')
task_queue.append('任务2')
task_queue.append('任务3')
while task_queue:
task = task_queue.popleft()
print(f"处理: {task}")
四、Counter——计数器
4.1 基本用法
Counter 是 dict 的子类,用于统计可哈希对象的数量。
from collections import Counter
# 从列表创建
words = ['a', 'b', 'c', 'a', 'b', 'a']
counter = Counter(words)
print(counter) # Counter({'a': 3, 'b': 2, 'c': 1})
# 从字符串创建
char_counter = Counter('hello world')
print(char_counter) # Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1})
# 手动计数
cnt = Counter()
cnt['a'] += 1
cnt['b'] += 2
print(cnt) # Counter({'b': 2, 'a': 1})
4.2 常用方法
from collections import Counter
c = Counter('abracadabra')
# 获取元素(按频率排序)
print(list(c.elements())) # ['a', 'a', 'a', 'a', 'a', 'b', 'b', 'r', 'r', 'c', 'd']
# 最常见的 n 个元素
print(c.most_common(2)) # [('a', 5), ('b', 2)]
# 获取计数(不存在返回 0,不报错)
print(c['z']) # 0
# 更新计数器
c.update('abc') # 添加新计数
print(c['a']) # 6
# 减去
c.subtract('a')
print(c['a']) # 5
# 算术运算
c1 = Counter('ab')
c2 = Counter('bc')
print(c1 + c2) # Counter({'b': 2, 'a': 1, 'c': 1})
print(c1 - c2) # Counter({'a': 1})
print(c1 & c2) # 交集(取最小值): Counter({'b': 1})
print(c1 | c2) # 并集(取最大值): Counter({'b': 1, 'a': 1, 'c': 1})
4.3 适用场景
# 实战:分析文章词频
from collections import Counter
import re
defword_frequency(text):
words = re.findall(r'\w+', text.lower())
return Counter(words)
text = "Python is great. Python is powerful. I love Python."
freq = word_frequency(text)
print(freq.most_common(3)) # [('python', 3), ('is', 2), ('great', 1)]
五、defaultdict——带默认值的字典
5.1 基本用法
defaultdict 在访问不存在的键时,不会抛出 KeyError,而是自动创建默认值。
from collections import defaultdict
# 使用 int 作为默认值(默认 0)
dd = defaultdict(int)
dd['a'] += 1
print(dd['a']) # 1
print(dd['b']) # 0(不存在,自动创建)
# 使用 list 作为默认值(默认 [])
dd_list = defaultdict(list)
dd_list['key'].append(1)
print(dd_list) # defaultdict(<class 'list'>, {'key': [1]})
# 使用自定义默认值
defdefault_value():
return'N/A'
dd_custom = defaultdict(default_value)
print(dd_custom['name']) # N/A
5.2 适用场景
- • 避免频繁的
if key not in dict 判断
# 实战:按首字母分组单词
from collections import defaultdict
words = ['apple', 'banana', 'cat', 'ant', 'bird', 'car']
grouped = defaultdict(list)
for word in words:
grouped[word[0]].append(word)
print(dict(grouped))
# {'a': ['apple', 'ant'], 'b': ['banana', 'bird'], 'c': ['cat', 'car']}
六、OrderedDict——有序字典
6.1 基本用法
OrderedDict 会记住键的插入顺序。在 Python 3.7+ 中,普通 dict 也保持插入顺序,但 OrderedDict 提供了额外的有序操作。
from collections import OrderedDict
od = OrderedDict()
od['a'] = 1
od['b'] = 2
od['c'] = 3
for key, value in od.items():
print(key, value) # 按插入顺序输出
# 移动元素
od.move_to_end('b') # 移到末尾
od.move_to_end('a', last=False) # 移到开头
# 弹出最后/最先
od.popitem() # 弹出最后
od.popitem(last=False) # 弹出最先
6.2 适用场景
# 实战:简单 LRU 缓存
from collections import OrderedDict
classLRUCache:
def__init__(self, capacity):
self.cache = OrderedDict()
self.capacity = capacity
defget(self, key):
if key notinself.cache:
return -1
self.cache.move_to_end(key)
returnself.cache[key]
defput(self, key, value):
if key inself.cache:
self.cache.move_to_end(key)
self.cache[key] = value
iflen(self.cache) > self.capacity:
self.cache.popitem(last=False)
七、其他工具
7.1 ChainMap——合并多个映射
from collections import ChainMap
dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 3, 'c': 4}
# 查找时按顺序查找,第一个匹配的优先
chain = ChainMap(dict1, dict2)
print(chain['a']) # 1
print(chain['b']) # 2(来自 dict1)
print(chain['c']) # 4
# 修改会影响第一个字典
chain['b'] = 100
print(dict1['b']) # 100
# 添加新映射
chain.new_child({'d': 5})
7.2 UserDict、UserList、UserString
这些类用于创建自定义的字典、列表、字符串子类,比直接继承内置类型更方便。
from collections import UserDict
classMyDict(UserDict):
def__setitem__(self, key, value):
print(f"设置 {key} = {value}")
super().__setitem__(key, value)
d = MyDict()
d['a'] = 1# 设置 a = 1
八、性能对比
九、实战案例
9.1 日志分析(Counter + defaultdict)
from collections import Counter, defaultdict
import re
log_data = """
192.168.1.1 - - [01/Jan/2025:10:00:00] "GET /index.html"
192.168.1.2 - - [01/Jan/2025:10:00:01] "GET /about.html"
192.168.1.1 - - [01/Jan/2025:10:00:02] "POST /login"
192.168.1.3 - - [01/Jan/2025:10:00:03] "GET /index.html"
192.168.1.1 - - [01/Jan/2025:10:00:04] "GET /index.html"
"""
# 统计 IP 访问次数
ip_pattern = r'(\d+\.\d+\.\d+\.\d+)'
ips = re.findall(ip_pattern, log_data)
ip_counter = Counter(ips)
print("IP 访问统计:")
for ip, count in ip_counter.most_common():
print(f" {ip}: {count}")
# 统计访问路径
path_pattern = r'"(?:GET|POST) (\S+)'
paths = re.findall(path_pattern, log_data)
path_counter = Counter(paths)
print("\n访问路径统计:")
for path, count in path_counter.most_common():
print(f" {path}: {count}")
9.2 任务调度(deque)
from collections import deque
import time
import threading
classTaskScheduler:
def__init__(self):
self.task_queue = deque()
self.running = True
defadd_task(self, task, delay=0):
self.task_queue.append((time.time() + delay, task))
# 按执行时间排序
self.task_queue = deque(sorted(self.task_queue, key=lambda x: x[0]))
defrun(self):
whileself.running andself.task_queue:
execute_time, task = self.task_queue[0]
if time.time() >= execute_time:
self.task_queue.popleft()
task()
else:
time.sleep(0.1)
defstop(self):
self.running = False
defjob1():
print(f"[{time.strftime('%H:%M:%S')}] 执行任务1")
defjob2():
print(f"[{time.strftime('%H:%M:%S')}] 执行任务2")
scheduler = TaskScheduler()
scheduler.add_task(job1, 1)
scheduler.add_task(job2, 2)
# scheduler.run()
9.3 图形数据结构(namedtuple)
from collections import namedtuple
# 定义图形元素
Point = namedtuple('Point', ['x', 'y'])
Circle = namedtuple('Circle', ['center', 'radius'])
Rect = namedtuple('Rect', ['x', 'y', 'width', 'height'])
defarea(shape):
ifisinstance(shape, Circle):
return3.14159 * shape.radius ** 2
elifisinstance(shape, Rect):
return shape.width * shape.height
return0
# 使用
c = Circle(Point(0, 0), 5)
r = Rect(0, 0, 10, 20)
print(f"圆面积: {area(c):.2f}")
print(f"矩形面积: {area(r)}")
十、总结
| | |
namedtuple | | |
deque | | |
Counter | | |
defaultdict | | |
OrderedDict | | |
ChainMap | | |
核心要点:
- •
namedtuple 适合替代简单类,提高可读性。 - •
deque 用于队列和栈,特别是频繁的头部操作。 - • Python 3.7+ 中
dict 已有序,OrderedDict 仍可用于需要 move_to_end 等操作的场景。
掌握 collections 模块,可以让你用更少的代码解决复杂的数据结构问题,写出更优雅、高效的 Python 代码。