0
点赞
收藏
分享

微信扫一扫

Python 中 collections 模快

君心浅语 2022-04-30 阅读 30

文章目录

Collections 模快

一、 简介

collections模块实现了特定目标的容器,以提供Python标准内建容器dict ,list , set , 和tuple的替代选择

通俗来说,Python内置的数据类型和方法,collections模块在这些内置类型的基础提供了额外的高性能数据类型,比如基础的字典是不支持顺序的,collections模块的OrderedDict类构建的字典可以支持顺序,collections模块的这些扩展的类用处非常大,熟练掌握该模块,可以大大简化Python代码

官方文档:【https://docs.python.org/zh-cn/3/library/collections.html】

所有子类

名称功能
namedtuple()创建命名元组子类的工厂函数
deque类似列表(list)的容器,实现了在两端快速添加(append)和弹出(pop)
ChainMap类似字典(dict)的容器类,将多个映射集合到一个视图里面
Counter字典的子类,提供了可哈希对象的计数功能
OrderedDict字典的子类,保存了他们被添加的顺序
defaultdict字典的子类,提供了一个工厂函数,为字典查询提供一个默认值
UserDict封装了字典对象,简化了字典子类化
UserList封装了列表对象,简化了列表子类化
UserString封装了字符串对象,简化了字符串子类化

二、 Counter

1、 基本用法

一个计数器工具提供快速和方便的计数,Counter是一个dict的子类,用于计数可哈希对象。它是一个集合,元素像字典键(key)一样存储,它们的计数存储为值。计数可以是任何整数值,包括0和负数,Counter类有点像其他语言中的bags或multisets。简单说,就是对可迭代对象的里面每个元素的计数

lis = ["blue", "blue", "blue", "red", "red", "green", "green", "blue", "red", "red"]
# 传统方法计数
count_lis = {}
for i in lis:
    if count_lis.get(i, -1) == -1:
        # 说明获取值失败,没有存入值
        count_lis[i] = 1
        continue
    count_lis[i] += 1
print(count_lis)

# 使用Counter计数
from collections import Counter
count = Counter(lis)  # 参数是可迭代对象
print(dict(count))  

# 也可以是
coun = Counter(a=4, c=5)  # 表示有4个a,5个c
print(coun)

2、 常用函数

函数作用
del count[key]删除指定键key
count.elements()返回一个迭代器
most_common(n)返回一个列表,其中包含 n 个最常见的元素及出现次数
subtract(iterable or mapping)从迭代对象或映射对象减去元素。但是是减去,而不是替换
update(iterable or mapping)从迭代对象或映射对象添加元素
clean()清空里面的内容
get(key)得到对应键的值
items()得到对象内所有的键值对
from collections import Counter
lis = ["blue", "blue", "blue", "red", "red", "green", "green", "blue", "red", "red"]
count = Counter(lis)  # 参数是可迭代对象
count.update(["r", "s", "r"])  # 向里面添加元素
del(count["r"])  # 删除键"r"
print(count.elements())  # 返回可迭代对象
print(count.most_common(3))  # 只输出前三个数量最多的元素
count.subtract(["z", "r", "r"])  # 减去里面的元素,注意,不是删除
print(count.items())  # 得到键值对
count.clear()  # 清空内容

3、 数学运算

加和减,结合计数器,通过加上或者减去元素的相应计数。交集和并集返回相应计数的最小或最大值。每种操作都可以接受带符号的计数,但是输出会忽略掉结果为零或者小于零的计数

from collections import Counter
count = Counter(a=3, b=-4)  # 参数是可迭代对象
c_div = Counter(a=1, b=2, c=3)  # 创建一个新的对象

print(count)
# 进行数学操作,如果c_div有count里面的键,则进行相应的数学运算
print(count - c_div)
print(count + c_div)

# 单目数学运算
print(+count)  # 只取值为正数的键
print(-count)  # 对负数取反,并且正数忽略

# 进行逻辑运算
print(count & c_div)  # 交集运算
print(count | c_div)  # 并集运算

# 比较运算
print(count == c_div)  # 其为判断每一个键值对是否相同

三、 deque

双端队列,可以快速的从另外一侧追加和推出对象,deque是一个双向链表,针对list连续的数据结构插入和删除进行优化。它提供了两端都可以操作的序列,这表示在序列的前后你都可以执行添加或删除操作。双向队列(deque)对象支持以下方法:

方法作用
append(x)添加元素到右端
appendleft(x)添加元素到左端
clear()清空所有的元素
copy()浅拷贝
count(x)计算值为x出现的次数
extend(iterable)拓展队列的右侧
extendleft(iterable)拓展队列的左侧,反顺序添加
index(x[, start[, end]])返回元素 x 的索引
insert(i, x)x 位置插入元素 i
pop()删除最右边的元素并返回该元素
popleft()删除最左边的元素并返回该元素
remove(val)移除队列中的第一个 val 元素
reverse()逆序排列
rotate(n)向右循环移动 n 步。 如果 n 是负数,就向左循环
maxlen返回队列的最大长度

四、 OrderedDict

有序词典就像常规词典一样,但有一些与排序操作相关的额外功能,popitem() 方法有不同的签名。它接受一个可选参数来指定弹出哪个元素。move_to_end() 方法,可以有效地将元素移动到任一端

与dict字典的不同之处:

  • 常规的dict被设计为非常擅长映射操作,跟踪插入顺序是次要的
  • OrderedDict旨在擅长重新排序操作。空间效率、迭代速度和更新操作的性能是次要的
  • 算法上,OrderedDict可以比dict更好地处理频繁的重新排序。这使其适用于跟踪最近的访问
  • 对于OrderedDict,相等操作检查匹配顺序
  • OrderedDict类的popitem()方法有不同的签名。它接收一个可选参数来指定弹出哪个元素
  • OrderedDict类有一个move_to_end()方法,可以有效地将元素移动到任意一端
  • Python 3.8之前,dict缺少__reversed__()方法

OrderedDict特殊功能

方法作用
popitem(last=True)将对象中的元素从一侧移除,并返回移除的键值对
move_to_end(key, last=True)将现有键移动到有序字典的任一端
reversed(OrderedDict)有序字典提供了逆序迭代的支持

五、 nametuple

1、 简介

生成可以使用名字来访问元素内容的tuple子类,命名元组赋予每个位置一个含义,提供可读性和自文档性。它们可以用于任何普通元组,并添加了通过名字获取值的能力,通过索引值也是可以的

2、 构造函数

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

3、 常用方法

为了防止字段冲突,方法和属性以下划线开始

方法作用
_make(iterable)类方法从存在的序列或迭代实例中创建一个新实例
_asdict()返回一个新的dict,它将字段名称映射到它们对应的值
_replace(**kwargs)返回一个新的命名元组实例,并将指定域替换为新的值
_fields字符串元组列出了字段名,用于提醒和从现有元组创建一个新的命名元组类型
_field_defaults字典将字段名映射到默认值
getattr()获取对应元素的属性值
from collections import namedtuple
tup = namedtuple('tup', ['a', 'b', 'v'], rename=True, defaults=[8, 9, 10])  # 创建对象
print(tup._field_defaults)  # 给字段名设置defaults里面的默认值
tup = tup(0, 1, 2)  # 给里面的字段名赋值
print(getattr(tup, "a"), tup.a)  # 获取属性值
print(tup._fields)  # 获取字段名

六、 defaultdict

1、 简介

在普通的字典中,获取一个key有两种方法,第一个使用get(key),第二种是通过索引来获取值

当使用索引来获取键值对时,如果应用的key不存在,就会抛出KeyError。如果希望key不存在时,返回一个默认值,就可以用defaultdict

2、 构造函数

defaultdict(default_factory=None, /[, ...])

返回一个新的类似字典的对象。defaultdict是内置dict类的子类。它重载了一个方法并添加可写的实例变量。其余功能与dict类相同

default_factory:第一个参数用于为该属性提供初始值,默认为None。所有其他参数(包括关键字参数)都相当于传递给dict的构造函数,还支持一下方法作为扩展:__missing__(key)

  • 如果default_factory属性为None,则调用本方法会抛出KeyError异常,附带参数key

  • 如果default_factory不为None,则它被(不带参数地)调用来为key提供一个默认值,这个值和key作为一对键值对被插入到字典中,并作为本方法的返回值返回

3、 default_factory

如果不存在,该对象会自动插入一个默认数据类型来代替

3.1 list

使用 list 作为 default_factory,很轻松地将(键-值对组成的)序列转换为(键-列表组成的)字典

from collections import defaultdict

s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
# 第一种创建方法
d = defaultdict(list)
for k, v in s:
    d[k].append(v)

print(d)
print(d["green"])  # 如果不存在,返回空列表,并且创建该对象
print(sorted(d.items()))

# 第二种创建方法
d_ = {}
for k, v in s:
    d_.setdefault(k, []).append(v)

print(d_)

3.2 int

设置 default_factory为int,使defaultdict用于计数(类似其他语言中的 bag或multiset)

from collections import defaultdict

s = "mississippi"
# 创建方法
d = defaultdict(int)
for k in s:
    d[k] += 1  # 计数作用
print(d)

3.3 set

设置 default_factory 为 set 使 defaultdict 用于构建 set 集合

from collections import defaultdict

s = [('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue', 4)]
# 创建方法
d = defaultdict(set)
for k, v in s:
    d[k].add(v)
print(d)

3.4 自定义对象

from collections import defaultdict


class Test:

    def printN(self):
        print(self.n)

    def setN(self, i):
        self.n = i


name = "abcdefghij"
d = defaultdict(Test)
for i in range(10):
    d[name[i]].setN(i)
d["a"].printN()  # 输出数值
print(d)

七、 ChainMap

1、 简介

一个ChainMap类是为了将多个映射快速的链接到一起,这样它们就可以作为一个单元处理。它通常比创建一个新字典和多次调用 update() 要快很多

这个类可以用于模拟嵌套作用域,并且在模版化的时候比较有用

创建对象:

cm = ChainMap(*maps)  # 传入映射对象

2、 常用方法

方法作用
maps一个可以更新的映射列表
new_child(m=None, **kwargs)如果指定了m则添加映射到对象前面,返回新映射
parents返回一个新的 ChainMap 包含所有的当前实例的映射,跳过第一个映射

代码实例:

from collections import ChainMap

cm = ChainMap({"h": 1})
print(cm.maps)  # 返回列表
print(cm.new_child({"a": 2, "b": 3}))  # 添加映射
print(list(cm))  # 只返回键,不返回值
print(cm.new_child({"a": 2}).new_child({"b": 4}).parents)  # 返回除了第一个以外的其他对象

对于ChainMap对象,我们可以直接使用键取值,也可以直接使用字典的其他方法,就像它是一个单一的字典

八、 UserDict

用作字典对象的外包装。对这个类的需求已部分由直接创建 dict 的子类的功能所替代;不过,这个类处理起来更容易,因为底层的字典可以作为属性来访问

dic = UserDict([initialdata]) 

九、 UserList

对这个类的需求已部分由直接创建list的子类的功能所替代;不过,这个类处理起来更容易,因为底层的列表可以作为属性来访问

lis = UserList([list])

子类化的要求: UserList 的子类需要提供一个构造器,可以无参数调用,或者一个参数调用。返回一个新序列的列表操作需要创建一个实现类的实例。它假定了构造器可以以一个参数进行调用,这个参数是一个序列对象,作为数据源

如果一个分离的类不希望依照这个需求,所有的特殊方法就必须重写;请参照源代码进行修改

十、 UserString

用作字符串对象的外包装。对这个类的需求已部分由直接创建 str的子类的功能所替代;不过,这个类处理起来更容易,因为底层的字符串可以作为属性来访问

str_ =  UserString(seq)
举报

相关推荐

0 条评论