Python的collections模块真的很好用


Posted in Python onMarch 01, 2021

collections是实现了特定目标的容器,以提供Python标准内建容器 dict , list , set , 和 tuple 的替代选择。为了让大家更好的认识,本文详细总结collections的相关知识,一起来学习吧!

Python的collections模块真的很好用

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

Counter:字典的子类,提供了可哈希对象的计数功能。

defaultdict:字典的子类,提供了一个工厂函数,为字典查询提供了默认值。

OrderedDict:字典的子类,保留了他们被添加的顺序。

namedtuple:创建命名元组子类的工厂函数。

deque:类似列表容器,实现了在两端快速添加(append)和弹出(pop)。

ChainMap:类似字典的容器类,将多个映射集合到一个视图里面。

Counter

Counter是一个dict子类,主要是用来对你访问的对象的频率进行计数。

>>> import collections
>>> # 统计字符出现的次数
... collections.Counter('hello world')
Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1})
>>> # 统计单词个数
... collections.Counter('hello world hello lucy'.split())
Counter({'hello': 2, 'world': 1, 'lucy': 1})

常用方法:

elements():返回一个迭代器,每个元素重复计算的个数,如果一个元素的计数小于1,就会被忽略。

most_common([n]):返回一个列表,提供n个访问频率最高的元素和计数

subtract([iterable-or-mapping]):从迭代对象中减去元素,输入输出可以是0或者负数

update([iterable-or-mapping]):从迭代对象计数元素或者从另一个 映射对象 (或计数器) 添加。

>>> c = collections.Counter('hello world hello lucy'.split())
>>> c
Counter({'hello': 2, 'world': 1, 'lucy': 1})
>>> # 获取指定对象的访问次数,也可以使用get方法
... c['hello']
2
>>> # 查看元素
... list(c.elements())
['hello', 'hello', 'world', 'lucy']
>>> c1 = collections.Counter('hello world'.split())
>>> c2 = collections.Counter('hello lucy'.split())
>>> c1
Counter({'hello': 1, 'world': 1})
>>> c2
Counter({'hello': 1, 'lucy': 1})
>>> # 追加对象,+或者c1.update(c2)
... c1+c2
Counter({'hello': 2, 'world': 1, 'lucy': 1})
>>> # 减少对象,-或者c1.subtract(c2)
... c1-c2
Counter({'world': 1})
>>> # 清除
... c.clear()
>>> c
Counter()

defaultdict

返回一个新的类似字典的对象。defaultdict 是内置 dict 类的子类。

class collections.defaultdict([default_factory[, ...]])

>>> d = collections.defaultdict()
>>> d
defaultdict(None, {})
>>> e = collections.defaultdict(str)
>>> e
defaultdict(<class 'str'>, {})

例子

defaultdict的一个典型用法是使用其中一种内置类型(如str、int、list或dict等)作为默认工厂,这些内置类型在没有参数调用时返回空类型。

>>> e = collections.defaultdict(str)
>>> e
defaultdict(<class 'str'>, {})
>>> e['hello']
''
>>> e
defaultdict(<class 'str'>, {'hello': ''})
>>> # 普通字典调用不存在的键时,报错
... e1 = {}
>>> e1['hello']
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
KeyError: 'hello'

使用 int 作为 default_factory

>>> fruit = collections.defaultdict(int)
>>> fruit['apple'] = 2
>>> fruit
defaultdict(<class 'int'>, {'apple': 2})
>>> fruit['banana'] # 没有对象时,返回0
0
>>> fruit
defaultdict(<class 'int'>, {'apple': 2, 'banana': 0})

使用 list 作为 default_factory

>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = collections.defaultdict(list)
>>> for k,v in s:
...   d[k].append(v)
...
>>> d
defaultdict(<class 'list'>, {'yellow': [1, 3], 'blue': [2, 4], 'red': [1]})
>>> d.items()
dict_items([('yellow', [1, 3]), ('blue', [2, 4]), ('red', [1])])
>>> sorted(d.items())
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]

使用 dict 作为 default_factory

```python
>>> nums = collections.defaultdict(dict)
>>> nums[1] = {'one':1}
>>> nums
defaultdict(, {1: {'one': 1}})
>>> nums[2]
{}
>>> nums
defaultdict(, {1: {'one': 1}, 2: {}})

使用 set 作为 default_factory

```python
>>> types = collections.defaultdict(set)
>>> types['手机'].add('华为')
>>> types['手机'].add('小米')
>>> types['显示器'].add('AOC')
>>> types
defaultdict(<class 'set'>, {'手机': {'华为', '小米'}, '显示器': {'AOC'}})

## OrderedDict

Python字典中的键的顺序是任意的,它们不受添加的顺序的控制。

collections.OrderedDict 类提供了保留他们添加顺序的字典对象。

```python
>>> o = collections.OrderedDict()
>>> o['k1'] = 'v1'
>>> o['k3'] = 'v3'
>>> o['k2'] = 'v2'
>>> o
OrderedDict([('k1', 'v1'), ('k3', 'v3'), ('k2', 'v2')])

如果在已经存在的 key 上添加新的值,将会保留原来的 key 的位置,然后覆盖 value 值。

```python
>>> o['k1'] = 666
>>> o
OrderedDict([('k1', 666), ('k3', 'v3'), ('k2', 'v2')])
>>> dict(o)
{'k1': 666, 'k3': 'v3', 'k2': 'v2'}

## namedtuple

三种定义命名元组的方法:第一个参数是命名元组的构造器(如下的:Person1,Person2,Person3)

```python
>>> P1 = collections.namedtuple('Person1',['name','age','height'])
>>> P2 = collections.namedtuple('Person2','name,age,height')
>>> P3 = collections.namedtuple('Person3','name age height')

实例化命名元组

```python
>>> lucy = P1('lucy',23,180)
>>> lucy
Person1(name='lucy', age=23, height=180)
>>> jack = P2('jack',20,190)
>>> jack
Person2(name='jack', age=20, height=190)
>>> lucy.name # 直接通过 实例名.属性 来调用
'lucy'
>>> lucy.age
23

deque

collections.deque 返回一个新的双向队列对象,从左到右初始化(用方法 append()),从 iterable(迭代对象)数据创建。如果 iterable 没有指定,新队列为空。

collections.deque 队列支持线程安全,对于从两端添加(append)或者弹出(pop),复杂度O(1)。

虽然 list 对象也支持类似操作,但是这里优化了定长操作(pop(0)、insert(0,v))的开销。

如果 maxlen 没有指定或者是 None ,deque 可以增长到任意长度。否则,deque 就限定到指定最大长度。一旦限定长度的 deque 满了,当新项加入时,同样数量的项就从另一端弹出。

支持的方法:

append(x):添加x到右端。

appendleft(x):添加x到左端。

clear():清除所有元素,长度变为0。

copy():创建一份浅拷贝。

count(x):计算队列中个数等于x的元素。

extend(iterable):在队列右侧添加iterable中的元素。

extendleft(iterable):在队列左侧添加iterable中的元素,注:在左侧添加时,iterable参数的顺序将会反过来添加。

index(x[,start[,stop]]):返回第 x 个元素(从 start 开始计算,在 stop 之前)。返回第一个匹配,如果没找到的话,抛出 ValueError 。

insert(i,x):在位置 i 插入 x 。注:如果插入会导致一个限长deque超出长度 maxlen 的话,就抛出一个 IndexError 。

pop():移除最右侧的元素。

popleft():移除最左侧的元素。

remove(value):移去找到的第一个 value。没有抛出ValueError。

reverse():将deque逆序排列。返回 None 。

maxlen:队列的最大长度,没有限定则为None。

>>> d = collections.deque(maxlen=10)
>>> d
deque([], maxlen=10)
>>> d.extend('python')
>>> [i.upper() for i in d]
['P', 'Y', 'T', 'H', 'O', 'N']
>>> d.append('e')
>>> d.appendleft('f')
>>> d.appendleft('g')
>>> d.appendleft('h')
>>> d
deque(['h', 'g', 'f', 'p', 'y', 't', 'h', 'o', 'n', 'e'], maxlen=10)
>>> d.appendleft('i')
>>> d
deque(['i', 'h', 'g', 'f', 'p', 'y', 't', 'h', 'o', 'n'], maxlen=10)
>>> d.append('m')
>>> d
deque(['h', 'g', 'f', 'p', 'y', 't', 'h', 'o', 'n', 'm'], maxlen=10)

## ChainMap

问题背景是我们有多个字典或者映射,想把它们合并成为一个单独的映射,有人说可以用update进行合并,这样做的问题就是新建了一个数据结构以致于当我们对原来的字典进行更改的时候不会同步。如果想建立一个同步的查询方法,可以使用 ChainMap。

可以用来合并两个或者更多个字典,当查询的时候,从前往后依次查询。简单使用:

```python
>>> d1 = {'apple':1,'banana':2}
>>> d2 = {'orange':2,'apple':3,'pike':1}
>>> combined1 = collections.ChainMap(d1,d2)
>>> combined2 = collections.ChainMap(d2,d1)
>>> combined1
ChainMap({'apple': 1, 'banana': 2}, {'orange': 2, 'apple': 3, 'pike': 1})
>>> combined2
ChainMap({'orange': 2, 'apple': 3, 'pike': 1}, {'apple': 1, 'banana': 2})
>>> for k,v in combined1.items():
...   print(k,v)
...
orange 2
apple 1
pike 1
banana 2
>>> for k,v in combined2.items():
...   print(k,v)
...
apple 3
banana 2
orange 2
pike 1
</code></pre>

有一个注意点就是当对ChainMap进行修改的时候总是只会对第一个字典进行修改,如果第一个字典不存在该键,会添加。

<pre><code class="language-python line-numbers">>>> d1 = {'apple':1,'banana':2}
>>> d2 = {'orange':2,'apple':3,'pike':1}
>>> c = collections.ChainMap(d1,d2)
>>> c
ChainMap({'apple': 1, 'banana': 2}, {'orange': 2, 'apple': 3, 'pike': 1})
>>> c['apple']
1
>>> c['apple'] = 2
>>> c
ChainMap({'apple': 2, 'banana': 2}, {'orange': 2, 'apple': 3, 'pike': 1})
>>> c['pike']
1
>>> c['pike'] = 3
>>> c
ChainMap({'apple': 2, 'banana': 2, 'pike': 3}, {'orange': 2, 'apple': 3, 'pike': 1})

从原理上面讲,ChainMap 实际上是把放入的字典存储在一个队列中,当进行字典的增加删除等操作只会在第一个字典上进行,当进行查找的时候会依次查找,new_child() 方法实质上是在列表的第一个元素前放入一个字典,默认是{},而 parents 是去掉了列表开头的元素。

```python
>>> a = collections.ChainMap()
>>> a['x'] = 1
>>> a
ChainMap({'x': 1})
>>> b = a.new_child()
>>> b
ChainMap({}, {'x': 1})
>>> b['x'] = 2
>>> b
ChainMap({'x': 2}, {'x': 1})
>>> b['y'] = 3
>>> b
ChainMap({'x': 2, 'y': 3}, {'x': 1})
>>> a
ChainMap({'x': 1})
>>> c = a.new_child()
>>> c
ChainMap({}, {'x': 1})
>>> c['x'] = 1
>>> c['y'] = 1
>>> c
ChainMap({'x': 1, 'y': 1}, {'x': 1})
>>> d = c.parents
>>> d
ChainMap({'x': 1})
>>> d is a
False
>>> d == a
True

>>> a = {'x':1,'z':3}
>>> b = {'y':2,'z':4}
>>> c = collections.ChainMap(a,b)
>>> c
ChainMap({'x': 1, 'z': 3}, {'y': 2, 'z': 4})
>>> c.maps
[{'x': 1, 'z': 3}, {'y': 2, 'z': 4}]
>>> c.parents
ChainMap({'y': 2, 'z': 4})
>>> c.parents.maps
[{'y': 2, 'z': 4}]
>>> c.parents.parents
ChainMap({})
>>> c.parents.parents.parents
ChainMap({})

到此这篇关于Python的collections模块真的很好用的文章就介绍到这了,更多相关Python的collections模块内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
浅析Python中else语句块的使用技巧
Jun 16 Python
一篇文章读懂Python赋值与拷贝
Apr 19 Python
Python中pillow知识点学习
Apr 30 Python
python学生管理系统学习笔记
Mar 19 Python
Python3基础教程之递归函数简单示例
Jun 07 Python
对python中GUI,Label和Button的实例详解
Jun 27 Python
如何安装并使用conda指令管理python环境
Jul 10 Python
python多进程并行代码实例
Sep 30 Python
Python 从attribute到property详解
Mar 05 Python
python 使用多线程创建一个Buffer缓存器的实现思路
Jul 02 Python
PyQt5的QWebEngineView使用示例
Oct 20 Python
tensorflow2.0教程之Keras快速入门
Feb 20 Python
Python  Asyncio模块实现的生产消费者模型的方法
Mar 01 #Python
Python创建自己的加密货币的示例
Mar 01 #Python
python 实现网易邮箱邮件阅读和删除的辅助小脚本
Mar 01 #Python
详解Django中的FBV和CBV对比分析
Mar 01 #Python
Python3压缩和解压缩实现代码
Mar 01 #Python
python re模块常见用法例举
Mar 01 #Python
Python实现简单的2048小游戏
Mar 01 #Python
You might like
用PHP连接Oracle数据库
2006/10/09 PHP
做一个有下拉功能的留言版
2006/10/09 PHP
支持ie与FireFox的剪切板操作代码
2009/09/28 Javascript
javascript写的一个链表实现代码
2009/10/25 Javascript
iframe自适应宽度、高度 ie6 7 8,firefox 3.86下测试通过
2010/07/29 Javascript
JavaScript中使用构造函数实现继承的代码
2010/08/12 Javascript
javascript动画对象支持加速、减速、缓入、缓出的实现代码
2012/09/30 Javascript
node+express+jade制作简单网站指南
2014/11/26 Javascript
学习JavaScript鼠标响应事件
2015/12/25 Javascript
微信JS-SDK自定义分享功能实例详解【分享给朋友/分享到朋友圈】
2016/11/25 Javascript
js 递归和定时器的实例解析
2017/02/03 Javascript
jQuery选择器之子元素过滤选择器
2017/09/28 jQuery
vue.js实例对象+组件树的详细介绍
2017/10/20 Javascript
vue-router 组件复用问题详解
2018/01/22 Javascript
Mint-UI时间组件起始时间问题及时间插件使用
2018/08/20 Javascript
全面了解JavaScript的作用域链
2019/04/03 Javascript
iSlider手机端图片滑动切换插件使用详解
2019/12/24 Javascript
node.js中 redis 的安装和基本操作示例
2020/02/10 Javascript
javascript如何使用函数random来实现课堂随机点名方法详解
2020/07/28 Javascript
基于javascript实现移动端轮播图效果
2020/12/21 Javascript
[01:01]青春无憾,一战成名——DOTA2全国高校联赛开启
2018/02/25 DOTA
Python实现根据IP地址和子网掩码算出网段的方法
2015/07/30 Python
Python之reload流程实例代码解析
2018/01/29 Python
网易2016研发工程师编程题 奖学金(python)
2019/06/19 Python
Python 使用 prettytable 库打印表格美化输出功能
2019/12/26 Python
Python 将 QQ 好友头像生成祝福语的实现代码
2020/05/03 Python
简单了解python列表和元组的区别
2020/05/14 Python
python如何求100以内的素数
2020/05/27 Python
2020年10款优秀的Python第三方库,看看有你中意的吗?
2021/01/12 Python
pycharm 关闭search everywhere的解决操作
2021/01/15 Python
Stylenanda中文站:韩国一线网络服装品牌
2016/12/22 全球购物
亲属关系公证书
2014/04/08 职场文书
考勤制度通知
2015/04/25 职场文书
上帝为你开了一扇窗之Tkinter常用函数详解
2021/06/02 Python
聊聊mysql都有哪几种分区方式
2022/04/13 MySQL
Windows Server 2019 域控制器安装图文教程
2022/04/28 Servers