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下os模块强大的重命名方法renames详解
Mar 07 Python
Python实现比较扑克牌大小程序代码示例
Dec 06 Python
python3+PyQt5自定义视图详解
Apr 24 Python
Python 判断奇数偶数的方法
Dec 20 Python
对python操作kafka写入json数据的简单demo分享
Dec 27 Python
django 链接多个数据库 并使用原生sql实现
Mar 28 Python
python 数据分析实现长宽格式的转换
May 18 Python
详解pandas.DataFrame.plot() 画图函数
Jun 14 Python
如何用Matplotlib 画三维图的示例代码
Jul 28 Python
python 利用Pyinstaller打包Web项目
Oct 23 Python
pytorch 计算Parameter和FLOP的操作
Mar 04 Python
Python捕获、播放和保存摄像头视频并提高视频清晰度和对比度
Apr 14 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写入数据到CSV文件的方法
2015/03/14 PHP
纯PHP代码实现支付宝批量付款
2015/12/24 PHP
PHP实现时间比较和时间差计算的方法示例
2017/07/24 PHP
PHP实现的基于单向链表解决约瑟夫环问题示例
2017/09/30 PHP
详解php协程知识点
2018/09/21 PHP
php实现 master-worker 守护多进程模式的实例代码
2019/07/20 PHP
jquery之empty()与remove()区别说明
2010/09/10 Javascript
jQuery.extend()的实现方式详解及实例
2013/06/29 Javascript
javascript设计模式之解释器模式详解
2014/06/05 Javascript
JavaScript设置body高度为浏览器高度的方法
2015/02/09 Javascript
js实现固定显示区域内自动缩放图片的方法
2015/07/18 Javascript
AngularJs concepts详解及示例代码
2016/09/01 Javascript
Vue.js中轻松解决v-for执行出错的三个方案
2017/06/09 Javascript
JS检测是否可以访问公网服务器功能代码
2017/06/19 Javascript
node.js基础知识小结
2018/02/26 Javascript
基于JS实现带动画效果的流程进度条
2018/06/01 Javascript
小程序实现搜索框
2020/06/19 Javascript
js中Function引用类型常见有用的方法和属性详解
2019/12/11 Javascript
es6中let和const的使用方法详解
2020/02/24 Javascript
9个JavaScript日常开发小技巧
2020/10/06 Javascript
写一个Vue loading 插件
2020/11/09 Javascript
three.js如何实现3D动态文字效果
2021/03/03 Javascript
Python使用lxml模块和Requests模块抓取HTML页面的教程
2016/05/16 Python
Python使用base64模块进行二进制数据编码详解
2018/01/11 Python
tensorflow训练中出现nan问题的解决
2018/02/10 Python
Django实现前台上传并显示图片功能
2020/05/29 Python
在pytorch中动态调整优化器的学习率方式
2020/06/24 Python
python 实现汉诺塔游戏
2020/11/28 Python
阿玛尼化妆品美国官网:Giorgio Armani Beauty
2017/02/02 全球购物
JD Sports法国:英国篮球和运动时尚的领导者
2017/09/28 全球购物
留学自荐信的技巧
2013/10/17 职场文书
国贸专业个人求职信范文
2014/01/08 职场文书
自动化毕业生专业自荐书范文
2014/02/04 职场文书
社区反邪教工作方案
2014/06/16 职场文书
学生未请假就回家检讨书
2014/09/22 职场文书
个人批评与自我批评范文
2014/10/17 职场文书