Python之collections模块

发布时间 2023-03-22 21:14:30作者: 我不知道取什么名字好

1. python的collections模块介绍

Python的collections模块是一个标准库,提供了一个集合的高性能容器,包含了许多内置容器的替代选择。这些容器拥有比内置的更多的功能,如默认值,有序元素和可命名元素等。

核心的数据类型包括

  • namedtuple():使用具名字段的元组,让元组更具可读性和自描述性
  • deque():高效的双向队列,适合在队列头和尾的频繁删除和添加数据
  • ChainMap():将多个字典或映射联合在一起来创建一个单独的映射
  • Counter():字典子类,提供了快速的计数功能
  • OrderedDict():字典子类,具有按元素插入顺序排序的功能
  • defaultdict():字典子类,提供了当元素不存在时默认值的功能
  • UserDictUserListUserString: 抽象类,可以方便地创建自定义的字典、列表、字符串等类型。
  • enum:枚举类,用于定义常量和枚举类型。

使用collections模块可以使编写Python代码更加方便。Python开发人员可以在代码中直接使用这些高效的数据类型来替代常规的容器和数据类型,以提高代码性能和可读性。

2. collections核心的数据类型

2.1 namedtuple具名字段的元组

namedtuple()是Python的collections模块中的一个工厂函数,用于创建具有命名属性的元组。它的目的是为了使代码更加可读和自描述性,避免硬编码元组的位置索引

使用namedtuple()创建的元组是一个新的类,这个类的实例与普通元组一样,但每个实例都有一个引用类的属性名

namedtuple()的语法如下

namedtuple(typename, field_names, *, verbose=False, rename=False, module=None)

其中:

  • typename用于命名新类。
  • field_names是一个字符串序列,用于指定字段名,可以使用空格、逗号或者是分号来分隔每个字段名。
  • namedtuple()的返回值是一个新的类,可以使用 namedtuple(typename)._fields 获取每个字段的名称。
from collections import namedtuple

# 定义一个具名元组类
Person = namedtuple("Person", ["name", "age", "gender"])

# 创建一个 Person 类的实例
person = Person("Alice", 28, "female")

# 访问某个属性
print(person.name)     # 输出:Alice
print(person.age)      # 输出:28
print(person.gender)   # 输出:female

# 通过索引访问属性
print(person[0])       # 输出:Alice
print(person[1])       # 输出:28
print(person[2])       # 输出:female

# 获取某个属性的值
print(getattr(person, "name"))    # 输出:Alice

# 将具名元组对象转换成字典对象
person_dict = person._asdict()
print(person_dict)               # 输出:{'name': 'Alice', 'age': 28, 'gender': 'female'}

# 通过字典创建具名元组类的实例
person_dict = {"name": "Bob", "age": 30, "gender": "male"}
person2 = Person(**person_dict)
print(person2)                   # 输出:Person(name='Bob', age=30, gender='male')

使用namedtuple()创建元组类实例之后,可以使用点符号来访问每个属性,也可以使用索引对其进行访问,这使得代码具有更好的可读性和自描述性。而不是使用传统的元组方式,例如t[0]t[1]t[2] 来代表不同的字段

2.2 deque高效的双向队列

deque():高效的双向队列,适合在队列头和尾的频繁删除和添加数据

deque 类是 Python collections 模块里的一个双向队列数据结构。deque 全名叫“double-ended queue”,即双端队列。它能高效的实现元素的插入和删除操作,并且支持从队列的两端进行插入和删除元素的操作。常用的方法还包括查找、计数和翻转等操作

from collections import deque

# 创建一个空的 deque 队列
d = deque()
print(d)     #deque([])

# 可以通过传入一个可迭代对象,创建一个 deque 队列
d1 = deque([1, 2, 3, 4, 5])
print(d1)    #deque([1, 2, 3, 4, 5])

# 在双端队列的左边添加元素
d.appendleft(0)
print(d)     #deque([0])

# 在双端队列的右边添加元素
d.append(6)
print(d)     #deque([0, 6])

# 扩展双端队列
d.extend([7, 8, 9])
print(d)     #deque([0, 6, 7, 8, 9])

# 扩展双端队列,从左边添加元素
d.extendleft([-1, -2, -3])
print(d)     #deque([-3, -2, -1, 0, 6, 7, 8, 9])

# 删除最左边的元素
d.popleft()#-3
print(d)   #deque([-2, -1, 0, 6, 7, 8, 9])

# 删除最右边的元素
d.pop()    #9
print(d)   #deque([-2, -1, 0, 6, 7, 8])

# 查找元素并返回所在位置的索引
print(d.index(-1))   # 1

# 返回元素出现的次数
print(d.count(3))    #0

# 反转 deque 队列
d.reverse()
print(d)    #deque([8, 7, 6, 0, -1, -2])

2.3 ChainMap多个字典的视图

ChainMap 类是 Python collections 模块中的一个字典类,用于将多个字典或映射联合在一起来创建一个单独的映射。它的目的是方便快捷地为多个字典或映射提供一个视图,并能够对合并后的映射进行修改。

from collections import ChainMap

# 创建多个字典
dict1 = {"a": "apple", "b": "banana"}
dict2 = {"c": "cat", "d": "dog"}
dict3 = {"e": "elephant", "f": "fox"}

# 使用 ChainMap 将多个字典合并
ch_map = ChainMap(dict1, dict2, dict3)

# 查找某个键对应的值
print(ch_map.get("a"))
print(ch_map.get("c"))
print(ch_map.get("e"))

# 修改某个键对应的值
dict1["a"] = "ant"
print(ch_map.get("a"))

# 新增某个键值对
dict2["g"] = "goose"
print(ch_map)

# 组合链
dict4 = {"a": "apple_new", "d": "dog_new"}
ch_map2 = ch_map.new_child(dict4)
print(ch_map2)

​ 上述示例中,创建了三个字典,使用 ChainMap 将它们合并,并演示了如何查找某个键对应的值、修改某个键对应的值、新增某个键值对,并演示了如何使用 new_child 方法新建一个组合链。其中 new_child 方法可以在当前 ChainMap 前面添加一个字典作为新的子字典,并返回一个新的 ChainMap 对象,新的子字典是在当前 ChainMap 对象之前的,因此可以优先从新的子字典中查找

2.4 Counter提供了快速的计数功能

Counter 类是 Python collections 模块中的一个计数器类,用于对可迭代对象中元素的出现次数进行计数,并以字典的形式返回计数结果。它的目的是为了快速高效地生成简单的统计报告。

from collections import Counter

# 使用 Counter 对当前列表中的元素进行计数
lst = ["apple", "banana", "apple", "apple", "orange", "banana", "pear"]
cnt = Counter(lst)  
print(cnt)   #Counter({'apple': 3, 'banana': 2, 'orange': 1, 'pear': 1})

# 查看某个元素在给定的列表中出现的次数
print(cnt["apple"])  #3
print(cnt["orange"]) #1
print(cnt["pear"])   #1
print(cnt["grape"])  #0

# 给 Counter 添加元素
cnt["grape"] = 2
print(cnt)  #Counter({'apple': 3, 'banana': 2, 'grape': 2, 'orange': 1, 'pear': 1})

# 获取计数结果中的最高频元素,并返回出现的次数
print(cnt.most_common(1))  #[('apple', 3)]
print(cnt.most_common(2))  #[('apple', 3), ('banana', 2)]

# 已知计数结果字典,获取对应的键
print(list(cnt.elements())) #['apple', 'apple', 'apple', 'banana', 'banana', 'orange', 'pear', 'grape', 'grape']

上述示例中,使用 Counter 对一个含有若干字符串元素的列表进行计数,并统计了每个字符串元素出现的次数。通过给 Counter 添加元素并使用 most_common 方法获取计数结果中的最高频元素,并统计它们出现的次数,最后使用 elements 方法获取计数结果中的所有键。

2.5 OrderedDict有序字典类(添加顺序)

OrderedDict 类是 Python collections 模块中的一个有序字典类,用于创建一个有序的键值对的字典。与 Python 内置的字典类相比,它能够记住键值对的添加顺序,保持顺序不变,能够按照添加顺序遍历键值对,非常适用于需要保持顺序的场景。

from collections import OrderedDict

# 创建一个空的 OrderedDict
od = OrderedDict()
print(od)     #OrderedDict()

# 创建一个有序字典
od1 = OrderedDict({
    "a": 1,
    "b": 2,
    "c": 3
})
print(od1)  #OrderedDict([('a', 1), ('b', 2), ('c', 3)])

# 添加元素进有序字典
od1["d"] = 4
od1["e"] = 5
print(od1)  #OrderedDict([('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5)])

# 把元素插入到有序字典中的指定位置
od1.update({"a": 0})
od1.move_to_end("b")
print(od1)  #OrderedDict([('a', 0), ('c', 3), ('d', 4), ('e', 5), ('b', 2)])

# 按照添加顺序遍历有序字典
for key, value in od1.items():
    print(key, value)

# 将有序字典转化为普通字典
d = dict(od1)
print(d)  #{'a': 0, 'c': 3, 'd': 4, 'e': 5, 'b': 2}

上述示例中,演示了创建空的和有元素的有序字典,并演示了如何向有序字典中添加、插入元素,并按照添加顺序遍历有序字典。还演示了如何将有序字典转化为普通字典,以及如何通过 move_to_end 方法改变有序字典中某个键的位置。

2.6 defaultdict 提供了当元素不存在时默认值的功能

defaultdict 类是 Python collections 模块中的一个字典类,与 Python 内置的字典类相比,在访问键不存在的数据项时,能够自动添加默认值,并且可以通过指定工厂函数来创建字典。使用 defaultdict 可以减少代码量,并且可以自定义默认的数据类型或值。

from collections import defaultdict

# 创建一个 defaultdict 对象
dd = defaultdict(int)

# 往 defaultdict 中添加元素
dd["a"] = 1
dd["b"] = 2
dd["c"] = 3

print(dd)  #defaultdict(<class 'int'>, {'a': 1, 'b': 2, 'c': 3})
print(dd["d"])  #0

# 利用 lambda 函数作为工厂函数来创建 defaultdict
dd2 = defaultdict(lambda: "None")

dd2["a"] = "apple"
dd2["b"] = "banana"

print(dd2) #defaultdict(<function <lambda> at 0x000001843DBE5D38>, {'a': 'apple', 'b': 'banana'})
print(dd2["c"])  #None

上述示例中,利用 defaultdict 创建了一个整数类型的字典,并向其中添加若干个元素。当访问字典中一个不存在的键时,返回的是 int 类型的默认值 0。另外,还利用 lambda 函数作为工厂函数来创建了一个字典,当访问字典的不存在的键时,返回的是 str 类型的默认值 'None'