当前位置: 首页 > news >正文

collections:容器数据类型

文章目录

  • 一、ChainMap:搜索多个字典
    • 1、访问值:与常规字典相同
    • 2、重排:maps属性
    • 3、更新值
      • (1) ChainMap与原字典相互影响
      • (2) new_child() 可以在ChainMap中构建额外字典
  • 二、Counter:统计元素出现频次
    • 1、初始化:元素序列 / 字典 / 关键字参数
    • 2、访问值
      • (1) 使用字典 API
      • (2) elements():逐一迭代输出元素
      • (3) most_common():最常出现的元素
    • 3、更新值:update()
    • 4、算术与集合操作:加、减、交、并
  • 三、defaultdict:对缺失键返回默认值
    • 1、setdefault():获取 / 设置键值(dict 内置方法)
    • 2、defaultdict:提前设置默认值
  • 四、deque:双端队列
    • 1、与list相同操作:索引、删除、确定长度
    • 2、填充:extend / append / extendleft / appendleft
    • 3、消费:pop / popleft
    • 4、旋转:rotate 截取续到另一端
    • 5、限制队列大小:maxlen 参数
  • 五、namedtuple:带命名字段的元组
    • 1、创建:namedtuple(类名, 元素信息)
    • 2、非法字段名:rename 参数解决冲突
    • 3、属性和方法:._fields / _asdict() / _replace()
  • 六、OrderedDict:有序字典
    • 1、相等性:考虑键值的插入顺序
    • 2、重排:move_to_end(键, last)
  • 七、collections.abc:容器的抽象基类

collections模块包含除内置类型 list、dict 和 tuple 以外的其他容器数据类型。

import collections

一、ChainMap:搜索多个字典

要点:

  • ChainMap类管理一个字典序列,并按照字典传递到构造函数的顺序来查找与键关联的值,支持常规字典的读数方法以及.keys()/.values()/.items()/key in dict方法。
  • maps属性中存储的是要搜索的字典列表list,该列表允许直接更改。
  • ChainMap实例与原字典相互影响,任何一方发生变化,都会影响另一方的访问值。
  • new_child()方法可以在ChainMap实例的最前面构建新字典,也可以向该方法直接传递现有字典。

1、访问值:与常规字典相同

ChainMap支持与常规字典dict相同的 API 来访问现有的值,键搜索不到时同样会触发KeyError

dict_a = {'a': 'A', 'c': 'C'}
dict_b = {'b': 'B', 'c': 'D'}dict_chain = collections.ChainMap(dict_a, dict_b)# 根据键直接访问值
# 键'c'在字典dict_a、dict_b中都存在,但是字典dict_a先出现,所以输出的是dict_a中对应的值'C'
print('a = ', dict_chain['a'])
print('b = ', dict_chain['b'])
print('c = ', dict_chain['c'])# 调用 .keys()、.values()、.items()方法
print('Keys =', list(dict_chain.keys()))
print('Values =', list(dict_chain.values()))
print('Items:')
for k, v in dict_chain.items():print('{} = {}'.format(k, v))# 判断键是否在字典中
print('"b" in m:', 'b' in dict_chain)
print('"d" in m:', 'd' in dict_chain)

2、重排:maps属性

maps属性中存储的是要搜索的字典列表list,可以直接修改该列表来增加新映射,或者改变元素的顺序来调整映射值。

dict_a = {'a': 'A', 'c': 'C'}
dict_b = {'b': 'B', 'c': 'D'}dict_chain = collections.ChainMap(dict_a, dict_b)# list类型,元素是「按照构造顺序排列的字典」
print(dict_chain.maps)# 反转maps列表后,字典dict_b在前,此时键'c'对应的值为'D'
# reversed()函数:返回给定序列的反向迭代器
dict_chain.maps = list(reversed(dict_chain.maps))
print('c = ', dict_chain['c'])

3、更新值

(1) ChainMap与原字典相互影响

如果用来构造ChainMap的原字典发生了变化,那么所构造的ChainMap在访问值时也会发生相应的变化。同样,也可以通过为ChainMap设置值来修改原字典的值。

dict_a = {'a': 'A', 'c': 'C'}
dict_b = {'b': 'B', 'c': 'D'}dict_chain = collections.ChainMap(dict_a, dict_b)# 改变字典dict_a的值,dict_chain也会受到影响
print('Before:', dict_chain['c'])
dict_a['c'] = 'E'
print('After :', dict_chain['c'])# 更新dict_chain中键'c'的值,会影响到字典dict_a
print('Before:', dict_chain)
dict_chain['c'] = 'F'
print('After :', dict_chain)
print('dict_a:', dict_a)

(2) new_child() 可以在ChainMap中构建额外字典

.new_child()方法可以在maps列表的最前面创建一个新字典,从而来避免修改现有的原字典。这样的好处是,可以很容易地在某次迭代中增加或更新键值,然后在下次迭代中丢弃这些改变。
如果新字典已知或者提前构建,也可以直接向.new_child()方法传递该字典。

dict_a = {'a': 'A', 'c': 'C'}
dict_b = {'b': 'B', 'c': 'D'}dict_chain1 = collections.ChainMap(dict_a, dict_b)
dict_chain2 = dict_chain1.new_child()# dict_chain2 before: ChainMap({}, {'a': 'A', 'c': 'C'}, {'b': 'B', 'c': 'D'})
print('dict_chain1 before:', dict_chain1)
print('dict_chain2 before:', dict_chain2)dict_chain2['c'] = 'E'# 不会修改字典dict_a和dict_b
# dict_chain2 after: ChainMap({'c': 'E'}, {'a': 'A', 'c': 'C'}, {'b': 'B', 'c': 'D'})
print('dict_chain1 after:', dict_chain1)
print('dict_chain2 after:', dict_chain2)# 新字典已知,直接向new_child()方法传递参数
dict_c = {'c': 'F'}
dict_chain2 = dict_chain1.new_child(dict_c)
print('dict_chain1["c"] = ', dict_chain1['c'])
print('dict_chain2["c"] = ', dict_chain2['c'])
# 等价于下列代码
# 在list前面加星号*,相当于解包(unpack)该列表,将其元素展开为独立的参数或元素
dict_chain2 = collections.ChainMap(dict_c, *dict_chain1.maps)

二、Counter:统计元素出现频次

Counter是一个容器,用于统计可迭代对象中元素的出现次数,它返回一个类似字典的对象,其中元素是键,计数是值。

1、初始化:元素序列 / 字典 / 关键字参数

Counter支持3种形式的初始化:

  1. 提供元素序列
  2. 提供包含元素键和计数值的字典
  3. 使用关键字参数将元素名映射到计数值
print(collections.Counter(['a', 'b', 'c', 'a', 'b', 'b']))
print(collections.Counter({'a': 2, 'b': 3, 'c': 1}))
print(collections.Counter(a=2, b=3, c=1))>>> 输出结果:Counter({'b': 3, 'a': 2, 'c': 1})

当然了,也可以使用collections.Counter()直接构造一个空Counter

2、访问值

(1) 使用字典 API

Counter支持与常规字典dict相同的 API 来访问现有的值,键搜索不到时不会触发KeyError,而是返回数字0。

c = collections.Counter('abcdaab')# 结果:3
print(c['a'])
# 结果:0
print(c['f'])

(2) elements():逐一迭代输出元素

elements()方法返回一个迭代器,该迭代器将生成Counter知道的所有正计数值元素。

需要注意的是:<1> 元素的输出顺序无法保证;<2> 输出的是元素而不是类别,例如元素a的计数值是3,那么它将会被输出3次;<3> 不会输出计数值小于等于0的元素

c = collections.Counter('abdcaab')
c['z'] = 0
print(list(c.elements()))>>> 输出结果:['a', 'a', 'a', 'b', 'b', 'd', 'c']

(3) most_common():最常出现的元素

most_common()方法用于统计最常出现的 n 个元素及相应计数,返回一个列表list。如果不向该方法传递参数,则会生成一个由所有元素构成、按照计数值逆序排列的列表,包含非正数计数值的元素

c = collections.Counter('abdcaabasdnsadfnakscihciecweikfvcweifbacsacoplwffmsdv')
c['z'] = -1# 输出结果:[('a', 8), ('c', 7), ('s', 5)]
print(c.most_common(3))
# 输出结果:[('a', 8), ('c', 7), ('s', 5), ('f', 5), ('d', 4), ('i', 4), ('b', 3), ('e', 3), ('w', 3), ('n', 2), ('k', 2), ('v', 2), ('h', 1), ('o', 1), ('p', 1), ('l', 1), ('m', 1), ('z', -1)]
print(c.most_common())

3、更新值:update()

使用update()方法可以更新现有Counter中的元素和计数值,可以向该方法传入序列或字典。与常规字典不同,最终的计数值为传参相应的计数值 + 原来计数值,而非替换。

c = collections.Counter()# 当前结果:Counter({'a': 3, 'b': 2, 'c': 1, 'd': 1})
c.update('abcdaab')
# 当前结果:Counter({'d': 6, 'a': 4, 'b': 2, 'c': 1})
c.update({'a': 1, 'd': 5})

4、算术与集合操作:加、减、交、并

Counter实例支持用算术和集合操作来完成结果的聚集,也支持+=、-=、&=、|=等原地执行的操作符。注意,操作完成后,计数值为0或者负数的元素均会被删除

c1 = collections.Counter(['a', 'b', 'c', 'a', 'b', 'b'])
c2 = collections.Counter('alphabet')add_c = c1 + c2
sub_c = c1 - c2# 交集取计数值中的最小值
inter_c = c1 & c2
# 并集取计数值中的最大值
union_c = c1 | c2

三、defaultdict:对缺失键返回默认值

1、setdefault():获取 / 设置键值(dict 内置方法)

标准字典中包含一个setdefault()方法,用于安全地「获取或设置」字典的键值。如果键已经存在,则返回对应的值(不会修改字典);如果不存在,则为该键设置默认值,再返回该值。

person = {"name": "Alice", "age": 25}# "name" 已存在,直接返回原值'Alice',字典不会改变
print(person.setdefault("name", "Bob"))
# "gender" 不存在,设置默认值'Female'并返回,字典已经改变
print(person.setdefault("gender", "Female"))

2、defaultdict:提前设置默认值

collections模块中的defaultdict可以在初始化时让调用者提前指定默认值,也支持使用关键字参数指定初始存在的映射关系。

def default_factory():return 'default value'# 初始存在的映射关系 {'foo': 'bar'},缺失键的默认取值为 'default value'
d1 = collections.defaultdict(default_factory, foo='bar')
# 缺失键的默认取值为空列表
d2 = collections.defaultdict(list)

四、deque:双端队列

collections模块中的deque是一种序列容器,它支持从任意一端增加和删除元素。

1、与list相同操作:索引、删除、确定长度

deque同样支持list的一些操作,如索引、确定长度,以及从队列中删除元素。

d = collections.deque('abcdefg')print(len(d))
print(d[0])
print(d[-1])
d.remove('c')

2、填充:extend / append / extendleft / appendleft

可以从任意一端对deque进行填充:

# 从右端填充
d1 = collections.deque()
d1.extend('abcdefg')
print('extend    :', d1)
d1.append('h')
print('append    :', d1)# 从左端填充
d2 = collections.deque()
d2.extendleft(range(6))     # deque([5, 4, 3, 2, 1, 0])
d2.appendleft(6)

3、消费:pop / popleft

可以从任意一端对deque进行消费:

d1 = collections.deque('abcdefg')
d1.pop() # gd2 = collections.deque(range(6))
d2.popleft() # 0

4、旋转:rotate 截取续到另一端

使用rotate方法,可以将deque按照任意一个方向旋转:

  • 向该方法传递正整数值,会截取尾部一段序列,将其续到头部
  • 向该方法传递负整数值,会截取头部一段序列,将其续到尾部
d = collections.deque(range(10))
# 截取尾部两个元素,续到头部:deque([8, 9, 0, 1, 2, 3, 4, 5, 6, 7])
d.rotate(2)d = collections.deque(range(10))
# 截取头部两个元素,续到尾部:deque([2, 3, 4, 5, 6, 7, 8, 9, 0, 1])
d.rotate(-2)

5、限制队列大小:maxlen 参数

配置deque实例时可以通过maxlen参数指定队列的最大长度。在队列达到最大长度后,再增加新元素就会删除队列中的现有元素:从左端添加会逐渐删除右端的元素,从右端添加会逐渐删除左端的元素。

d = collections.deque([1, 9, 4], maxlen=3)# deque([9, 4, 2], maxlen=3)
d.append(2)# deque([3, 9, 4], maxlen=3)
d.appendleft(3)

五、namedtuple:带命名字段的元组

标准tuple使用数值索引来访问其中的元素,collections模块中的namedtuple所创建的元组不仅可以使用数值索引,还可以指定名字。

1、创建:namedtuple(类名, 元素信息)

通过namedtuple(类名, 元素名字符串)可以创建一个元组,这个元组本质上是一个类,因此,既可以使用数值索引来访问元素,也可以使用点记法元组.attr按照名字访问。

namedtuple的传参中:第一个参数是类名;第二个参数中包含了元素名信息,它的形式可以是「以空格或逗号间隔的元素名所构成的的字符串」,也可以是「包含元素名字符串的列表」。

Person = collections.namedtuple('Person', ['name', 'age'])bob = Person(name='Bob', age=30)
print(bob[1]) 	 # 30
jane = Person(name='Jane', age=29)
print(jane.name) # 'Jane'

与常规tuple类似,namedtuple也是不可修改的,因此它也可以被用作字典的键或者放在集合中。如果试图通过数字索引来改变值,会触发TypeError异常;如果试图通过命名属性来改变值,会触发AttributeError异常。

2、非法字段名:rename 参数解决冲突

字段名重复或者与 Python 关键字冲突,那么就是非法字段名。非法字段名会导致ValueError异常:

try:collections.namedtuple('Person', 'name class age')
except ValueError as err:# Type names and field names cannot be a keyword: 'class'print(err)try:collections.namedtuple('Person', 'name age age')
except ValueError as err:# Encountered duplicate field name: 'age'print(err)

在创建namedtuple时把其中的rename参数设置成True,就可以对非法字段重命名。非法字段的新名字为:下划线+对应的数字索引。

with_class = collections.namedtuple('Person', 'name class age', rename=True)
# ('name', '_1', 'age')
print(with_class._fields)two_ages = collections.namedtuple('Person', 'name, age,age', rename=True)
# ('name', 'age', '_2')
print(two_ages._fields)

3、属性和方法:._fields / _asdict() / _replace()

如上述代码所示,namedtuple的字段名保存在._fields属性中。而使用_asdict()方法可以将namedtuple实例转换为OrderedDict实例,OrderedDict的键与namedtuple的字段顺序相同:

Person = collections.namedtuple('Person', 'name age')bob = Person(name='Bob', age=30)
# {'name': 'Bob', 'age': 30}
print(bob._asdict())

_replace()方法可以替换一些字段的值,并产生一个新实例

Person = collections.namedtuple('Person', 'name age')bob = Person(name='Bob', age=30)
new = bob._replace(name='Robert')

六、OrderedDict:有序字典

在 Python 3.5及之前,常规的dict不会记住键的插入顺序。而collections模块中OrderedDict会记住向字典中插入键的顺序,并在创建迭代器的时候使用这个顺序。

1、相等性:考虑键值的插入顺序

常规的dict在检查相等性的时候只会查看其内容,但是OrderedDict还会考虑键值的插入顺序:

d1 = {}
d1['a'] = 'A'
d1['b'] = 'B'
d1['c'] = 'C'd2 = {}
d2['c'] = 'C'
d2['b'] = 'B'
d2['a'] = 'A'print(d1 == d2)  # Trued1 = collections.OrderedDict()
d1['a'] = 'A'
d1['b'] = 'B'
d1['c'] = 'C'd2 = collections.OrderedDict()
d2['c'] = 'C'
d2['b'] = 'B'
d2['a'] = 'A'print(d1 == d2)  # False

2、重排:move_to_end(键, last)

使用move_to_end()方法可以将OrderedDict中的键移至序列的起始或者末尾位置,来改变键的顺序,last参数可以控制将元素移至末端(参数值为True,默认值)还是起始(参数值为False):

d = collections.OrderedDict([('a', 'A'), ('b', 'B'), ('c', 'C')])# OrderedDict({'a': 'A', 'c': 'C', 'b': 'B'})
d.move_to_end('b')# OrderedDict({'a': 'A', 'c': 'C', 'b': 'B'})
d.move_to_end('b', last=False)

七、collections.abc:容器的抽象基类

collections.abc模块包含了一些抽象基类,这些基类:

  1. 为 Python 内置的容器数据结构以及collections模块定义的容器数据结构定义了 API;
  2. 可以在调用对象前使用isinstance()方法测试某个对象是否支持某个 API;
  3. 有些类提供了方法实现,可以直接继承这些类来构造定制容器类型,这样就不必从头实现每一个方法。

下表展示了这些抽象基类及其用途:

基类API用途
Container基本容器特性,如in操作符
Hashable增加了散列支持,可以为容器实例提供散列值
Iterable可以在容器内容上创建一个迭代器
IteratorIterable这是容器内容上的一个迭代器
GeneratorIterator为迭代器扩展了 PEP 342 的生成器协议
Sized为知道自己大小的容器增加方法
Callable可以作为函数来调用的容器
SequenceSized, Iterable, Container支持获取单个元素以及迭代和改变元素顺序
MutableSequenceSequence支持创建一个实例之后增加和删除元素
ByteStringSequence合并 bytes 和 bytearray 的 API
SetSized, Iterable, Container支持集合操作,如交集和并集
MutableSetSet增加了创建集合后管理集合内容的方法
MappingSized, Iterable, Container定义dict使用的只读 API
MutableMappingMapping定义创建映射后管理映射内容的方法
MappingViewSized定义从迭代器访问映射的视图 API
ItemsViewMappingView, Set视图 API 的一部分
KeysViewMappingView, Set视图 API 的一部分
ValuesViewMappingView视图 API 的一部分
Awaitableawait表达式中可用的对象的 API,如协程
CoroutineAwaitable实现协程协议的类的 API
AsyncIterableasync for(PEP 492 中定义)兼容的iterable的 API
AsyncIteratorAsyncIterable异步迭代器的 API
http://www.dtcms.com/a/332714.html

相关文章:

  • C语言——深入理解指针(四)
  • 完整技术栈分享:基于Hadoop+Spark的在线教育投融资大数据可视化分析系统
  • 使用XXL-SSO实现登录认证以及权限管控
  • 解决 MySQL 查询速度缓慢的问题
  • Filebeat 轻量级日志采集实践:安装、配置、多行合并、JSON 解析与字段处理
  • Java集合Map与Stream流:Map实现类特点、遍历方式、Stream流操作及Collections工具类方法
  • 【软件设计模式】前置知识类图、七大原则(精简笔记版)
  • C++ 调试报错 常量中有换行符
  • 基于桥梁三维模型的无人机检测路径规划系统设计与实现
  • Cursor 分析 bug 记录
  • 3D视觉与空间智能
  • imx6ull-驱动开发篇25——Linux 中断上半部/下半部
  • 智谱开源了最新多模态模型,GLM-4.5V
  • 关系型数据库从入门到精通:MySQL 核心知识全解析
  • 高并发系统性能优化实战:实现5万并发与毫秒级响应
  • Kafka生产者——提高生产者吞吐量
  • LeetCode 面试经典 150_数组/字符串_最长公共前缀(20_14_C++_简单)(暴力破解)(求交集)
  • 简单使用 TypeScript 或 JavaScript 创建并发布 npm 插件
  • 从零到一:发布你的第一个 npm 开源库(2025 终极指南)
  • IT资讯 | VMware ESXi高危漏洞影响国内服务器
  • Day62--图论--97. 小明逛公园(卡码网),127. 骑士的攻击(卡码网)
  • 嵌入式 C 语言编程规范个人学习笔记,参考华为《C 语言编程规范》
  • 使用CMAKE-GU生成Visual Studio项目
  • ​Visual Studio 2013.5 ULTIMATE 中文版怎么安装?iso镜像详细步骤
  • Pushgateway安装和部署,以及对应Prometheus调整
  • 六维力传感器:工业机器人的“触觉神经”如何突破自动化瓶颈?
  • Linux crontab定时任务
  • 3.1. CPU拓扑配置
  • 4.2 寻址方式 (答案见原书 P341)
  • Nginx蜘蛛请求智能分流:精准识别爬虫并转发SEO渲染服务