pin_drop当前位置:知识文库 ❯ 图文

Python标准库collections:高级容器类型

一、collections模块概述

collections 是Python标准库中提供的高级容器数据类型模块。它扩展了Python内置的dict、list、tuple等基础容器,提供了更专业、更高效的数据结构。无论是计数器、默认值字典、有序字典还是双端队列,collections模块都能让代码更简洁、更高效。

该模块包含以下核心类型:Counter(计数器)、defaultdict(默认值字典)、OrderedDict(有序字典)、deque(双端队列)、namedtuple(命名元组)和 ChainMap(映射链)。


二、核心容器类型

1. Counter - 计数器

代码示例

from collections import Counter

# 创建计数器
c = Counter(iterable)          # 从可迭代对象创建
c = Counter(dict)              # 从字典创建
c = Counter(keyword=value)     # 从关键字参数创建

# 常用方法
c.most_common(n)               # 返回n个最常见元素
c.elements()                   # 返回所有元素的迭代器
c.update(iterable)             # 更新计数
c.subtract(iterable)           # 减少计数

2. defaultdict - 默认值字典

代码示例

from collections import defaultdict

# 创建默认值字典
dd = defaultdict(default_factory)  # 指定默认值工厂函数

# 常用工厂函数
dd = defaultdict(list)             # 默认值为空列表
dd = defaultdict(int)              # 默认值为0
dd = defaultdict(set)              # 默认值为空集合
dd = defaultdict(lambda: "N/A")   # 默认自定义值

3. OrderedDict - 有序字典

代码示例

from collections import OrderedDict

# 创建有序字典
od = OrderedDict()
od = OrderedDict(iterable)

# 特殊方法
od.move_to_end(key, last=True)     # 移动键到末尾/开头
od.popitem(last=True)              # 弹出最后一个/第一个键值对

4. deque - 双端队列

代码示例

from collections import deque

# 创建双端队列
dq = deque(iterable, maxlen=None)

# 常用方法
dq.append(x) / dq.appendleft(x)    # 右端/左端添加
dq.pop() / dq.popleft()            # 右端/左端弹出
dq.rotate(n)                       # 旋转队列
dq.extend(iterable)                # 扩展队列

5. namedtuple - 命名元组

代码示例

from collections import namedtuple

# 创建命名元组类
Point = namedtuple('Point', ['x', 'y'])
# 或
Point = namedtuple('Point', 'x y')

# 创建实例
p = Point(1, 2)
print(p.x, p.y)  # 通过属性访问
容器类型 主要用途 与普通类型的区别
Counter 计数统计 自动统计元素出现次数
defaultdict 避免KeyError 访问不存在的键时自动创建默认值
OrderedDict 保持插入顺序 支持移动键位置和有序弹出
deque 高效两端操作 两端操作均为O(1)时间复杂度
namedtuple 创建轻量级对象 可通过属性名访问,内存占用小

三、基本用法详解

Counter 统计词频

代码示例

from collections import Counter

text = "python is great python is fun python is powerful"
words = text.split()

# 统计词频
word_counts = Counter(words)
print("词频统计:")
print(word_counts)

# 获取最常见的3个词
print("\n最常见的3个词:")
print(word_counts.most_common(3))

# 从列表创建
numbers = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
num_counts = Counter(numbers)
print("\n数字频率:")
print(num_counts.most_common())

defaultdict 分组数据

代码示例

from collections import defaultdict

# 按首字母分组单词
words = ["apple", "banana", "avocado", "cherry", "blueberry", "apricot"]

# 使用defaultdict,无需检查键是否存在
groups = defaultdict(list)
for word in words:
    groups[word[0]].append(word)

print("按首字母分组:")
for letter, words_list in groups.items():
    print(f"  {letter}: {words_list}")

# 统计每个学生的成绩
scores = defaultdict(list)
records = [
    ("张三", 85), ("李四", 92), ("张三", 78),
    ("王五", 90), ("李四", 88), ("张三", 95)
]

for name, score in records:
    scores[name].append(score)

print("\n学生成绩:")
for name, score_list in scores.items():
    avg = sum(score_list) / len(score_list)
    print(f"  {name}: {score_list}, 平均: {avg:.1f}")

deque 双端队列操作

代码示例

from collections import deque

# 创建双端队列
dq = deque([1, 2, 3, 4, 5])
print(f"初始队列: {dq}")

# 两端操作
dq.append(6)          # 右端添加
dq.appendleft(0)      # 左端添加
print(f"添加后: {dq}")

dq.pop()              # 右端弹出
dq.popleft()          # 左端弹出
print(f"弹出后: {dq}")

# 旋转
dq.rotate(2)          # 向右旋转2步
print(f"右旋2步: {dq}")

dq.rotate(-1)         # 向左旋转1步
print(f"左旋1步: {dq}")

# 限制长度(自动丢弃)
limited_dq = deque(maxlen=3)
for i in range(5):
    limited_dq.append(i)
print(f"限制长度为3的队列: {limited_dq}")

四、完整代码示例

示例1:使用namedtuple创建数据结构

代码示例

from collections import namedtuple

# 定义学生命名元组
Student = namedtuple('Student', ['name', 'age', 'grade', 'major'])

# 创建学生实例
students = [
    Student("张三", 20, 85, "计算机科学"),
    Student("李四", 21, 92, "数学"),
    Student("王五", 19, 78, "物理"),
    Student("赵六", 22, 95, "计算机科学"),
]

# 按成绩排序
sorted_students = sorted(students, key=lambda s: s.grade, reverse=True)
print("按成绩排序:")
for student in sorted_students:
    print(f"  {student.name} ({student.major}): {student.grade}分")

# 查找特定专业的学生
cs_students = [s for s in students if s.major == "计算机科学"]
print(f"\n计算机科学专业学生: {[s.name for s in cs_students]}")

示例2:文本分析工具

代码示例

from collections import Counter, defaultdict
import re

def analyze_text(text):
    """分析文本的词频、字符分布和常见搭配"""
    # 清理文本并分词
    words = re.findall(r'\b\w+\b', text.lower())
    
    # 词频统计
    word_freq = Counter(words)
    
    # 常见双词搭配
    bigrams = Counter(zip(words, words[1:]))
    
    # 按首字母分组
    alpha_groups = defaultdict(list)
    for word in set(words):
        alpha_groups[word[0]].append(word)
    
    return {
        "total_words": len(words),
        "unique_words": len(word_freq),
        "top_10_words": word_freq.most_common(10),
        "top_5_bigrams": bigrams.most_common(5),
        "alphabet_groups": dict(alpha_groups)
    }

# 测试文本
sample_text = """
Python is a great programming language. Python is used in web development,
data science, artificial intelligence, and automation. Python is easy to
learn and has a large community. Many companies use Python for their projects.
"""

result = analyze_text(sample_text)
print(f"总词数: {result['total_words']}")
print(f"唯一词数: {result['unique_words']}")
print(f"\n前10高频词:")
for word, count in result['top_10_words']:
    print(f"  {word}: {count}")
print(f"\n前5常见搭配:")
for (w1, w2), count in result['top_5_bigrams']:
    print(f"  {w1} {w2}: {count}")

示例3:实现LRU缓存

代码示例

from collections import OrderedDict

class LRUCache:
    """使用OrderedDict实现LRU缓存"""
    
    def __init__(self, capacity):
        self.cache = OrderedDict()
        self.capacity = capacity
    
    def get(self, key):
        """获取缓存值,如果存在则移到末尾(最近使用)"""
        if key not in self.cache:
            return None
        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:
            removed = self.cache.popitem(last=False)
            print(f"缓存已满,删除: {removed[0]}")
    
    def display(self):
        """显示当前缓存状态"""
        print(f"缓存内容: {dict(self.cache)}")

# 测试LRU缓存
cache = LRUCache(3)
cache.put("A", 1)
cache.put("B", 2)
cache.put("C", 3)
cache.display()

cache.get("A")  # 访问A,A变为最近使用
cache.put("D", 4)  # 超出容量,删除B(最久未使用)
cache.display()

print(f"获取A: {cache.get('A')}")
print(f"获取B: {cache.get('B')}")  # B已被删除

示例4:Counter的数学运算

代码示例

from collections import Counter

# 两个计数器
c1 = Counter(a=3, b=1, c=5)
c2 = Counter(a=1, b=2, d=3)

print("c1:", c1)
print("c2:", c2)

# 加法:合并计数
print(f"\n相加: {c1 + c2}")

# 减法:相减(只保留正数)
print(f"相减: {c1 - c2}")

# 交集:取最小值
print(f"交集: {c1 & c2}")

# 并集:取最大值
print(f"并集: {c1 | c2}")

# 实际例子:对比两个用户的兴趣爱好
user1_interests = Counter(["python", "javascript", "react", "python", "django"])
user2_interests = Counter(["python", "java", "react", "python", "spring"])

common = user1_interests & user2_interests
print(f"\n共同兴趣: {list(common.elements())}")

五、注意事项与最佳实践

注意1:Python 3.7+ 的内置 dict 已经保持插入顺序。如果只需要保持顺序,普通dict已足够;OrderedDict 的优势在于 move_to_end() 和有序 popitem() 功能。

注意2deque 的两端操作时间复杂度为 O(1),而列表的 pop(0)insert(0, x)O(n)。需要频繁操作队列时应使用deque。

注意3Counter 减法运算可能产生负值计数,使用 c1 - c2 会自动过滤掉零和负值,但直接修改计数(c[key] -= n)不会自动过滤。

注意4namedtuple 是不可变的,创建后不能修改字段值。如果需要可变版本,可以考虑使用 dataclass(Python 3.7+)。

小贴士

Python 3.7+ 的 dataclasses 模块可以作为 namedtuple 的现代替代品,支持默认值、可变字段、类型注解等更丰富的功能。对于新的项目,推荐优先使用 @dataclass 装饰器来创建数据类。


六、小结

  • Counter:专门用于计数统计,支持 most_common() 和数学运算

  • defaultdict:自动为不存在的键创建默认值,避免KeyError

  • OrderedDict:支持键顺序操作,适合实现LRU缓存

  • deque:双端队列,两端操作均为O(1),适合队列和栈

  • namedtuple:创建轻量级不可变对象,可通过属性名访问


七、练习题

练习1

编写一个程序,读取一个文本文件,使用Counter统计最常见的10个单词,并按出现频率降序输出。

练习2

使用deque实现一个滑动窗口最大值算法:给定一个整数数组和一个窗口大小k,找出每个滑动窗口中的最大值。

练习3

使用namedtuple或dataclass创建一个"商品"数据结构,包含名称、价格、库存等字段。编写函数实现:按价格排序、按库存筛选、计算总库存价值等功能。

常见问题

Python 3.7+还需要使用OrderedDict吗?

如果只是需要保持插入顺序,普通dict已经足够(Python 3.7+保证)。但如果你需要 move_to_end() 或有序的 popitem() 功能,或者需要反向迭代(reversed(od)),仍然需要使用OrderedDict。

deque和list有什么区别?什么时候用deque?

deque 在两端添加和弹出的操作时间复杂度为 O(1),而list的 pop(0)O(n)。当需要频繁在列表头部插入/删除元素时(如实现队列),应使用deque。如果只在末尾操作,list更高效。

Counter的most_common()返回列表还是字典?

most_common(n) 返回一个列表,列表中的每个元素是 (元素, 计数) 元组,按计数降序排列。如果不传参数,返回所有元素。Counter本身是dict的子类,可以像字典一样使用。

defaultdict的默认工厂函数什么时候被调用?

只有当访问一个不存在的键时,默认工厂函数才会被自动调用。例如 dd = defaultdict(list) 中,当访问 dd['new_key'] 时,会自动调用 list() 创建一个空列表并返回。使用 get() 方法不会触发工厂函数。

标签: collections Counter defaultdict deque 标准库 数据结构

本文涉及AI创作

内容由AI创作,请仔细甄别

list快速访问

上一篇: Python标准库re:正则表达式完全指南 下一篇: Python标准库itertools详解

poll相关推荐