器→工具, 编程语言

Python标准库之容器数据类型Collections

钱魏Way · · 13 次浏览

collections 模块是 Python 标准库中的一个模块,提供了高效的容器数据类型,这些类型扩展了 Python 内置的标准数据类型,如列表、字典和元组。collections 模块中的数据结构不仅提高了代码的可读性,还在特定的应用场景中提高了性能。

collections模块中的数据类型包括:

  • 命名元组(NamedTuple)。命名元组(在Python 3.6+中通过NamedTuple引入,Python 3.7+中直接集成到collections模块)提供了一种类似于元组的容器,但它允许你通过属性名而非索引来访问元素。这使得代码更加清晰和易于维护。
  • 计数器(Counter)。Counter是一个字典的子类,用于计数可哈希对象。它是一个集合,其中元素被存储为字典的键,而它们的计数作为字典的值。Counter类提供了一系列方法来方便地处理计数数据,如计算元素的总和、更新计数、以及计算两个Counter对象的交集、并集和差集。
  • 有序字典(OrderedDict)。OrderedDict是一个字典的子类,它记住了元素被添加到字典中的顺序。当迭代OrderedDict时,元素将按照它们被添加的顺序返回,这与普通字典不同,后者不保证元素的顺序。
  • 默认字典(DefaultDict)。DefaultDict为字典中的每个键提供了一个默认值。当你尝试访问一个不存在的键时,DefaultDict会返回该键对应的默认值,而不是抛出一个KeyError。这避免了在访问字典之前需要显式地检查键是否存在的需要。
  • 双端队列(deque)。deque(发音为“deck”或“double-ended queue”)是一个双端队列,它支持从两端快速添加(append)和弹出(pop)元素。这使得deque成为实现队列和栈的理想选择,同时也适用于其他需要高效插入和删除操作的场景。
  • 链式映射(ChainMap)。ChainMap允许你将多个字典链接在一起,这样你就可以将它们当作一个单一字典来查找值。当在一个ChainMap中查找键时,它会在链接的字典中从左到右查找,直到找到该键为止。这对于在多个字典中查找数据而不希望合并它们时非常有用。
  • 用户定义的映射类型(UserDict, UserList, UserString)。虽然这些类在Python 3.3及以后版本中被标记为过时(建议使用abc中的抽象基类来创建自定义容器),但它们曾经提供了一种方式,允许用户以面向对象的方式创建自定义的字典、列表和字符串类型。现在,推荐使用collections.abc模块中的MutableMapping、MutableSequence和MutableSet等抽象基类来定义自定义容器。

namedtuple()

namedtuple() 是一个工厂函数,用于创建具有命名字段的元组子类。它使得元组的每个字段可以通过名字而不仅仅是索引来访问。

主要特点:

  • 字段访问:可以通过字段名称访问值,如x。
  • 不变性:命名元组是不可变的,创建后不能更改其中的元素。
  • 可迭代:可以像普通元组一样迭代。
  • 自定义方法:可以定义 __repr__() 和 __str__() 方法以便于打印和调试。

用法:

from collections import namedtuple

# 创建一个名为 'Point' 的命名元组
Point = namedtuple('Point', ['x', 'y'])

# 创建一个 Point 实例
p = Point(10, 20)

# 访问字段
print(p.x)  # 输出: 10
print(p.y)  # 输出: 20

deque

deque(双端队列)是一个线程安全的、可以从两端快速添加和删除元素的双端队列数据结构。与列表相比,deque 在两端的操作时间复杂度为 O(1),而列表在头部操作时间复杂度为 O(n)。

主要特点:

  • 双端操作:支持从两端快速添加和删除元素。
  • 旋转操作:支持向左或向右旋转元素。
  • 线程安全:适用于多线程环境。

用法:

from collections import deque

# 创建一个 deque 实例
d = deque([1, 2, 3])

# 从右侧添加元素
d.append(4)
print(d)  # 输出: deque([1, 2, 3, 4])

# 从左侧添加元素
d.appendleft(0)
print(d)  # 输出: deque([0, 1, 2, 3, 4])

# 从右侧删除元素
d.pop()
print(d)  # 输出: deque([0, 1, 2, 3])

# 从左侧删除元素
d.popleft()
print(d)  # 输出: deque([1, 2, 3])

# 旋转 deque
d.rotate(1)  # 向右旋转
print(d)  # 输出: deque([3, 1, 2])
d.rotate(-1)  # 向左旋转
print(d)  # 输出: deque([1, 2, 3])

Counter

Counter 是一个子类化的字典,用于计数可哈希对象。它的主要用途是统计元素的出现频率。

主要特点:

  • 计数功能:自动处理计数任务。
  • 常用操作:如 most_common() 方法可以获取出现频率最高的元素。
  • 支持数学运算:支持与其他 Counter 对象的加法、减法等运算。

用法:

from collections import Counter

# 创建一个 Counter 实例
c = Counter('abracadabra')

# 获取元素计数
print(c)  # 输出: Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1})

# 获取最常见的 2 个元素
print(c.most_common(2))  # 输出: [('a', 5), ('b', 2)]

# 更新计数
c.update('abc')
print(c)  # 输出: Counter({'a': 6, 'b': 3, 'r': 2, 'c': 2, 'd': 1})

# 减少计数
c.subtract('a')
print(c)  # 输出: Counter({'a': 5, 'b': 3, 'c': 2, 'r': 2, 'd': 1})

OrderedDict

OrderedDict 是一个字典的子类,它保留了元素的插入顺序。标准字典在 Python 3.7 之后也保持插入顺序,但在之前的版本中,OrderedDict 提供了这个功能。

主要特点:

  • 保持顺序:保留元素的插入顺序。
  • 方法支持:提供 move_to_end() 方法来改变元素的位置。

用法:

from collections import OrderedDict

# 创建一个 OrderedDict 实例
od = OrderedDict()
od['a'] = 1
od['b'] = 2
od['c'] = 3

# 输出按插入顺序排列的字典
print(od)  # 输出: OrderedDict([('a', 1), ('b', 2), ('c', 3)])

# 插入新元素
od['d'] = 4
print(od)  # 输出: OrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 4)])

# 移动到末尾
od.move_to_end('a')
print(od)  # 输出: OrderedDict([('b', 2), ('c', 3), ('d', 4), ('a', 1)])

defaultdict

defaultdict 是 dict 的一个子类,它提供了一个默认值工厂函数。如果尝试访问字典中不存在的键,会自动使用工厂函数创建一个默认值。

主要特点:

  • 自动默认值:当访问不存在的键时,自动生成默认值。
  • 灵活工厂函数:可以使用各种工厂函数,如 list、int、set 等。

用法:

from collections import defaultdict

# 创建一个 defaultdict 实例,默认值为列表
dd = defaultdict(list)

# 添加元素
dd['a'].append(1)
dd['b'].append(2)
dd['a'].append(3)

print(dd)  # 输出: defaultdict(<class 'list'>, {'a': [1, 3], 'b': [2]})

# 默认值工厂函数返回的默认值
print(dd['c'])  # 输出: []

ChainMap

ChainMap 是一个字典视图,用于将多个字典或映射合并为一个视图。它允许你在多个映射之间进行查找操作,而不需要实际合并这些映射。

主要特点:

  • 虚拟合并:将多个映射合并为一个视图。
  • 查找顺序:查找时按照创建顺序从前到后。

用法:

from collections import ChainMap

# 创建多个字典
dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 3, 'c': 4}

# 创建 ChainMap 实例
cm = ChainMap(dict1, dict2)

# 查找值
print(cm['a'])  # 输出: 1
print(cm['b'])  # 输出: 2 (dict1 中的值覆盖了 dict2 中的值)
print(cm['c'])  # 输出: 4

# 添加新字典
dict3 = {'d': 5}
cm = cm.new_child(dict3)

print(cm['d'])  # 输出: 5

UserDict

UserDict 是一个用于创建自定义字典类的基类。它实际上是一个对内置字典对象的包装器,允许用户通过继承来实现自己的字典行为。

  • 实现: UserDict 内部维护一个实际的字典对象 data,所有的操作都会委托给这个字典。
  • 用途: 通过继承 UserDict,可以很容易地定制字典的行为,比如修改键值对的添加、删除、查找等操作。
from collections import UserDict

class MyDict(UserDict):
    def __setitem__(self, key, value):
        print(f'Setting {key} to {value}')
        super().__setitem__(key, value)

my_dict = MyDict()
my_dict['a'] = 10  # 输出: Setting a to 10

UserList

UserList 是一个用于创建自定义列表类的基类。类似于 UserDict,它是对内置列表的包装,提供了一个简单的方式来定制列表的行为。

  • 实现: UserList 维护一个实际的列表对象 data,所有的操作都会委托给这个列表。
  • 用途: 继承 UserList 可以定制列表的添加、删除、排序等操作。
from collections import UserList

class MyList(UserList):
    def append(self, item):
        print(f'Appending {item}')
        super().append(item)

my_list = MyList()
my_list.append(1)  # 输出: Appending 1

UserString

UserString 是一个用于创建自定义字符串类的基类。它是对内置字符串的包装,允许用户定制字符串的操作。

  • 实现: UserString 内部维护一个字符串对象 data,所有的字符串操作都会委托给这个对象。
  • 用途: 继承 UserString 可以定制字符串的拼接、替换、大小写转换等操作。
from collections import UserString

class MyString(UserString):
    def __str__(self):
        return self.data.upper()

my_string = MyString("hello")
print(my_string)  # 输出: HELLO

参考链接:

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注