杰瑞科技汇

Python collections库有哪些实用模块?

collections 是 Python 内置的一个模块,它提供了许多非常有用的、用于替代和增强标准内建容器(如 dict, list, set, tuple)的特化数据容器,这些容器针对特定场景进行了优化,可以让我们写出更简洁、更高效、更健壮的代码。

Python collections库有哪些实用模块?-图1
(图片来源网络,侵删)

为什么需要 collections

标准的 Python 容器功能强大,但在某些特定场景下,它们可能不是最优的选择。

  • 字典 (dict):查找、插入和删除的平均时间复杂度是 O(1),非常高效,但如果你想按元素插入的顺序来遍历它,或者希望字典的键默认有某种特定行为(如自动排序),标准字典就无法满足需求。
  • 列表 (list):作为动态数组,它非常灵活,但如果你需要频繁地在头部或中间插入/删除元素,其时间复杂度是 O(n),效率较低,检查一个元素是否在列表中也需要 O(n) 的时间。

collections 模块正是为了解决这些痛点而设计的。


核心组件详解

collections 模块中最常用的组件包括:namedtuple, deque, Counter, OrderedDict, defaultdict, ChainMapUserDict/UserList/UserString,我们重点讲解前六个。

namedtuple - 命名元组

namedtuple 是一个工厂函数,用于创建一个带有字段名的元组子类,它结合了元组的不可变轻量级特性,以及字典的通过名称访问字段的便利性。

Python collections库有哪些实用模块?-图2
(图片来源网络,侵删)

用途:当你的数据是一个简单的、不可变的对象集合时,使用 namedtuple 比定义一个完整的类更简洁、更高效。

示例

from collections import namedtuple
# 定义一个命名元组类型 'Point',它有两个字段 'x' 和 'y'
Point = namedtuple('Point', ['x', 'y'])
# 创建实例
p1 = Point(11, y=22)
p2 = Point(1, 2)
# 像元组一样通过索引访问
print(p1[0])  # 输出: 11
# 像对象一样通过属性名访问 (这是最大的优点)
print(p1.x)   # 输出: 11
print(p1.y)   # 输出: 22
# 它仍然是元组,所以支持所有元组操作
print(p1 + p2) # 输出: Point(x=12, y=24)
# 获取字段名
print(Point._fields) # 输出: ('x', 'y')
# 将命名元组转换为字典
print(p1._asdict()) # 输出: {'x': 11, 'y': 22}

优点

  • 内存高效:比普通对象占用更少的内存。
  • 可读性好p.xp[0] 更清晰。
  • 不可变:保证了数据的安全性。

deque - 双端队列

deque (发音 "deck",即 "double-ended queue" ) 是一个类似列表的容器,但它从两端添加或删除元素都非常快,它在两端都有近似 O(1) 的时间复杂度。

Python collections库有哪些实用模块?-图3
(图片来源网络,侵删)

用途:实现高效的队列和栈数据结构,特别是在需要频繁从头部或尾部进行元素操作的场景。

示例

from collections import deque
# 创建一个 deque
d = deque(['a', 'b', 'c'])
print(d) # 输出: deque(['a', 'b', 'c'])
# 从右侧添加元素
d.append('d')
print(d) # 输出: deque(['a', 'b', 'c', 'd'])
# 从左侧添加元素
d.appendleft('x')
print(d) # 输出: deque(['x', 'a', 'b', 'c', 'd'])
# 从右侧移除元素
d.pop()
print(d) # 输出: deque(['x', 'a', 'b', 'c'])
# 从左侧移除元素
d.popleft()
print(d) # 输出: deque(['a', 'b', 'c'])
# 限制最大长度,当超出时,另一端的数据会被自动移除
d_max = deque(maxlen=3)
d_max.append(1)
d_max.append(2)
d_max.append(3)
print(d_max) # 输出: deque([1, 2, 3])
d_max.append(4)
print(d_max) # 输出: deque([2, 3, 4]) # 1 被自动移除了

优点

  • 高效的两端操作:比 list.pop(0) (O(n)) 快得多。

Counter - 计数器

Counter 是一个 dict 的子类,专门用于计数可哈希对象,它是一个无序的集合,元素是作为键,计数值作为值。

用途:统计一个序列中每个元素出现的次数。

示例

from collections import Counter
import re
# 统计单词列表
words = ['red', 'blue', 'red', 'green', 'blue', 'blue']
word_counts = Counter(words)
print(word_counts)
# 输出: Counter({'blue': 3, 'red': 2, 'green': 1})
# 访问计数
print(word_counts['blue']) # 输出: 3
print(word_counts['yellow']) # 输出: 0 (不会像普通dict一样报KeyError)
# 获取最常见的n个元素
print(word_counts.most_common(2)) # 输出: [('blue', 3), ('red', 2)]
# 更新计数
word_counts['red'] += 1
print(word_counts['red']) # 输出: 3
# 从一个可迭代对象更新
word_counts.update(['red', 'black'])
print(word_counts) # 输出: Counter({'blue': 3, 'red': 4, 'green': 1, 'black': 1})
# 元素之间的数学运算 ( +, -)
c1 = Counter(a=4, b=2, c=0)
c2 = Counter(a=1, b=2, c=3)
c3 = c1 + c2  # 相加,只保留正数计数
print(c3)     # 输出: Counter({'a': 5, 'b': 4, 'c': 3})
c4 = c1 - c2  # 相减,只保留正数计数
print(c4)     # 输出: Counter({'a': 3})

优点

  • 简洁易用:一行代码即可完成计数任务。
  • 功能丰富:提供 most_common() 等实用方法。

OrderedDict - 有序字典

OrderedDictdict 的一个子类,它记住了键值对被插入的顺序,在 Python 3.7 之前,标准的 dict 是无序的,从 Python 3.7 开始,dict 也默认保持插入顺序。OrderedDict 的主要价值在于:

  1. 兼容旧版 Python:确保代码在 Python 3.6 及更早版本中也能按预期工作。
  2. 特定操作OrderedDict 有一些 dict 没有的方法,如 move_to_end()

用途:需要明确依赖字典插入顺序的场景,或者在旧版 Python 中实现有序字典。

示例

from collections import OrderedDict
# 创建一个有序字典
od = OrderedDict()
od['a'] = 1
od['b'] = 2
od['c'] = 3
print(od)
# 输出 (在所有Python版本中): OrderedDict([('a', 1), ('b', 2), ('c', 3)])
# 遍历时会按照插入顺序
for key in od:
    print(key, end=' ') # 输出: a b c
# 将一个键移动到末尾
od.move_to_end('a')
print("\n", od) # 输出: OrderedDict([('b', 2), ('c', 3), ('a', 1)])
# 将一个键移动到开头
od.move_to_end('a', last=False)
print("\n", od) # 输出: OrderedDict([('a', 1), ('b', 2), ('c', 3)])
# 弹出时也按顺序
print(od.popitem(last=False)) # 输出: ('a', 1)

defaultdict - 默认字典

defaultdictdict 的子类,它为字典的键提供了一个默认的工厂函数,当你访问一个不存在的键时,它会自动调用这个工厂函数来创建一个默认值,而不是抛出 KeyError

用途:当你希望字典的键自动拥有一个默认值(如列表、0、空集合等)时,可以避免大量的 key in dict 检查和 dict.setdefault() 调用。

示例

from collections import defaultdict
# 方法1: 使用普通字典,代码繁琐
s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4)]
d = {}
for k, v in s:
    if k not in d:
        d[k] = []
    d[k].append(v)
print(d) # 输出: {'yellow': [1, 3], 'blue': [2, 4]}
# 方法2: 使用 defaultdict,代码简洁
d_default = defaultdict(list)
for k, v in s:
    d_default[k].append(v) # 如果键不存在,会自动创建一个空列表 []
print(d_default) # 输出: defaultdict(<class 'list'>, {'yellow': [1, 3], 'blue': [2, 4]})
# 计数器是 defaultdict 的一个典型用例
dd_int = defaultdict(int)
dd_int['a'] += 1
dd_int['b'] += 1
dd_int['a'] += 1
print(dd_int) # 输出: defaultdict(<class 'int'>, {'a': 2, 'b': 1})

ChainMap - 链式映射

ChainMap 将多个字典(或其他映射)组合在一起,形成一个单一的、可更新的视图,它本身并不创建一个新的字典,而是将多个字典链接起来,查找操作会按照字典被添加到 ChainMap 中的顺序进行。

用途:将多个配置源(如默认配置、用户配置、命令行参数)合并成一个视图,优先级由链的顺序决定。

示例

from collections import ChainMap
# 定义几个配置字典
defaults = {'color': 'gray', 'species': 'cat'}
user_prefs = {'color': 'black'}
cli_args = {'color': 'blue'}
# 将它们链接起来,后面的字典优先级更高
config = ChainMap(cli_args, user_prefs, defaults)
# 查找 'color',会从第一个字典开始找,直到找到为止
print(config['color'])  # 输出: blue (来自 cli_args)
print(config['species']) # 输出: cat (来自 defaults)
# 添加新键,会添加到第一个字典
config['name'] = 'Whiskers'
print(config['name']) # 输出: Whiskers
print(cli_args)       # 输出: {'color': 'blue', 'name': 'Whiskers'}
# 修改一个键,会修改第一个找到的该键
config['color'] = 'purple'
print(config['color']) # 输出: purple
print(cli_args)       # 输出: {'color': 'purple', 'name': 'Whiskers'}
# 获取所有底层字典的列表
print(config.maps)
# 输出: [{'color': 'purple', 'name': 'Whiskers'}, {'color': 'black'}, {'color': 'gray', 'species': 'cat'}]

总结与对比

数据结构 主要用途 时间复杂度 特点
namedtuple 创建轻量级的、不可变的数据对象 访问 O(1) 不可变,属性访问,内存高效
deque 高效的两端操作(队列、栈) 两端操作 O(1) 比列表在头部操作快得多
Counter 计数可哈希对象 插入/计数 O(1) dict子类,提供most_common()
OrderedDict 保持键值对插入顺序 查找 O(1) dict子类,兼容旧版,有move_to_end()
defaultdict 为不存在的键提供默认值 查找/插入 O(1) dict子类,避免KeyError,代码更简洁
ChainMap 合并多个映射视图 查找 O(N) (N是映射数量) 不创建新字典,用于合并配置

何时使用哪个?

  • 需要一个简单的、不可变的“数据类”吗? -> namedtuple
  • 需要一个高效的队列或栈吗? -> deque
  • 需要统计元素频率吗? -> Counter
  • 需要字典保持插入顺序吗?(或在旧版Python中) -> OrderedDict
  • 需要字典的键自动有默认值吗? -> defaultdict
  • 需要合并多个配置字典吗? -> ChainMap

掌握 collections 模块是提升 Python 编程能力的重要一步,它能让你在面对各种复杂问题时,拥有更优雅、更高效的解决方案。

分享:
扫描分享到社交APP
上一篇
下一篇