详解Python 中的容器 collections


Posted in Python onAugust 17, 2020

写在之前

我们都知道 Python 中内置了许多标准的数据结构,比如列表,元组,字典等。与此同时标准库还提供了一些额外的数据结构,我们可以基于它们创建所需的新数据结构。

Python 附带了一个「容器」模块 collections,它包含了很多的容器数据类型,今天我们来讨论其中几个常用的容器数据类型,掌握了这几个可以减少我们重复造轮子所带来的烦扰。

namedtuple

相信你已经熟悉了元组。一个元组相当于一个不可变的列表,你可以存储一个数据的序列。这里要说的 namedtuple(命名元组)和元组非常像,它们都不能修改自己的数据。说完了像,那么它们有哪些地方不像呢?

作为元组,为了获取其中的数据,我们需要使用整数作为索引:

>>> people = ('Rocky', 'python')
>>> print(people[0])
Rocky

而 namedtuple 把元组变成了一个针对简单任务的容器,我们不必使用整数索引来访问 namedtuple 的数据,反而可以像用字典一样访问 namedtuple。

>>> from collections import namedtuple
>>> people = namedtuple('people', 'name age like')
>>> Rocky = people(name = 'rocky', age = 23, like = 'python')
>>> print(Rocky)
people(name='rocky', age=23, like='python')
>>> print(Rocky.name)
rocky

一个 namedtuple 有两个必须的参数:元组名称和字段名称。在上面的代码中,我们的元组名称是 people,字段名称是 name,age,like。nametuple 让元组变的更加易读,很容易理解代码是做什么的,同样我们也不用使用整数索引来访问一个命名元组(上面代码我们用 name 访问了 namedtuple 中的数据),这让我们的代码更加容易维护。

但是你一定要记住的是,虽然它的用法很爽,但它还是一个元组!所以属性值在 namedtuple 中是不可变的。

我们在上面说过可以像用字典一样访问 namedtuple,那么当然也可以把它转为字典,具体操作如下所示:

>>> from collections import namedtuple
>>> people = namedtuple('people', 'name age like')
>>> Rocky = people(name = 'rocky', age = 23, like = 'python')
>>> print(Rocky._asdict())
OrderedDict([('name', 'rocky'), ('age', 23), ('like', 'python')])

defaultdict

我之前在使用字典的时候相当随意,只是随便 dict 一下就好了,然而这样使用存在一个问题:当使用的 key 不存在的时候会报 KeyError,而 defaultdict 就比较厉害了,我们完全不需要检查 key 是否存在,所以我们能像下面这样做的随心所欲:

from collections import defaultdict

languages = (
  ('rocky', 'python'),
  ('snow', 'c'),
  ('leey', 'java'),
  ('rocky', 'c++'),
  ('leey', 'c#')
)

favourite = defaultdict(list)

for name, language in languages:
  favourite[name].append(language)

print(favourite)

输出如下所示:

defaultdict(<type 'list'>, {'leey': ['java', 'c#'], 'rocky': ['python', 'c++'], 'snow': ['c']})

然后我们再回到“键不存在,会触发 KeyError 异常”这个问题上来,我们先来看 dict 触发 KeyError 的例子:

my_dict = {}
my_dict['name']['like'] = 'python'

输出如下:

KeyError: 'name'

defaultdict 则用了一个非常巧妙的方式绕过了这个问题,请看下面的操作:

import collections
language = lambda : collections.defaultdict(language)
my_dict = language()
my_dict['name']['like'] = 'python'

运行一下显示正常,我们可以用 json.dumps 打印出 my_dict 的内容:

import json
print(json.dumps(my_dict))

运行结果如下:

{"name": {"like": "python"}}

Counter

Counter 是一个计数器,它可以帮助我们针对某项数据进行计数,比如可以用它来统计每个人擅长的编程语言:

from collections import Counter

languages = (
('rocky', 'python'),
('snow', 'c'),
('leey', 'java'),
('rocky', 'c++'),
('leey', 'c#')
)

cnt = Counter(name for name, language in languages)
print(cnt)

运行结果如下所示:

Counter({'leey': 2, 'rocky': 2, 'snow': 1})

当然我们也可以用它来统计一个文件,比如:

from collections import Counter

with open('test.txt', 'rb') as f:
line_cnt = Counter(f)

print(line_cnt)

deque

deque 提供了一个双端队列,我们可以在首尾两端添加或者删除元素

想要使用 deque,首先我们要从 collections 中导入 deque 模块,然后创建一个 deque 对象,它的用法就像我们前面学过的 list 一样,并且提供了类似的方法,具体如下所示:

from collections import deque

deq = deque()
deq.append(1)
deq.append(2)
deq.append(3)
print(deq)
print(len(deq))
print(deq[0])
print(deq[-1])

输出结果如下:

deque([1, 2, 3])
3
1
3

我们可以从两端取出数据:

from collections import deque

deq = deque(range(5))
print('len(deq) == {}'.format(len(deq)))
deq.popleft()
deq.pop()
print(deq)

输出的结果如下所示:

len(deq) == 5
deq == deque([1, 2, 3])

我们也可以对这个列表的大小进行限制,当超出我们的限制的时候,数据会从另一端被 pop 出去,具体我们来看下面的操作:

from collections import deque

deq = deque(maxlen=3)
deq.append(1)
deq.append(2)
deq.append(3)
print(deq)
deq.append(4)
print (deq)

输出的结果如下:

deque([1, 2, 3], maxlen=3)
deque([2, 3, 4], maxlen=3)

当超出 maxlen 的值时,最左边的数据将从队列中删除。

当然我们还可以从任意一端扩展这个双端队列中的数据:

from collections import deque

deq = deque([1,2,3])
deq.extendleft([0])
deq.extend([4,5,6])
print(deq)

输出的结果如下所示:

deque([0, 1, 2, 3, 4, 5, 6])

以上就是详解Python 中的容器 collections的详细内容,更多关于python collections的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
Python使用urllib2获取网络资源实例讲解
Dec 02 Python
python在非root权限下的安装方法
Jan 23 Python
python爬虫爬取淘宝商品信息
Feb 23 Python
Python + Flask 实现简单的验证码系统
Oct 01 Python
vim自动补全插件YouCompleteMe(YCM)安装过程解析
Oct 21 Python
matplotlib绘制多个子图(subplot)的方法
Dec 03 Python
pytorch: Parameter 的数据结构实例
Dec 31 Python
Python线程条件变量Condition原理解析
Jan 20 Python
Python while循环使用else语句代码实例
Feb 07 Python
Python爬虫:Request Payload和Form Data的简单区别说明
Apr 30 Python
Python入门之使用pandas分析excel数据
May 12 Python
Django+Nginx+uWSGI 定时任务的实现方法
Jan 22 Python
Python 解析库json及jsonpath pickle的实现
Aug 17 #Python
Python实现爬取网页中动态加载的数据
Aug 17 #Python
Python 如何操作 SQLite 数据库
Aug 17 #Python
Python使用正则表达式实现爬虫数据抽取
Aug 17 #Python
Python 通过正则表达式快速获取电影的下载地址
Aug 17 #Python
Python 程序员必须掌握的日志记录
Aug 17 #Python
Python使用urlretrieve实现直接远程下载图片的示例代码
Aug 17 #Python
You might like
深入理解PHP之数组(遍历顺序)  Laruence原创
2012/06/13 PHP
destoon实现商铺管理主页设置增加新菜单的方法
2014/06/26 PHP
PHP实现的json类实例
2015/07/28 PHP
jQuery中文入门指南,翻译加实例,jQuery的起点教程
2007/02/09 Javascript
jquery键盘事件使用介绍
2011/11/01 Javascript
js控制表单奇偶行样式的简单方法
2013/07/31 Javascript
jQuery获取当前对象标签名称的方法
2014/02/07 Javascript
flash遮住div问题的正确解决方法
2014/02/27 Javascript
基于NodeJS的前后端分离的思考与实践(五)多终端适配
2014/09/26 NodeJs
Node.js中使用mongoskin操作mongoDB实例
2014/09/28 Javascript
文字垂直滚动之javascript代码
2015/07/29 Javascript
Javascript之BOM(window对象)详解
2016/05/25 Javascript
node.js 中国天气预报 简单实现
2016/06/06 Javascript
Javascript中函数名.length属性用法分析(对比arguments.length)
2016/09/16 Javascript
jQuery使用eraser.js插件实现擦除、刮刮卡效果的方法【附eraser.js下载】
2017/04/28 jQuery
vue环境搭建简单教程
2017/11/07 Javascript
Vue.js 实现数据展示全部和收起功能
2018/09/05 Javascript
解决v-for中使用v-if或者v-bind:class失效的问题
2018/09/25 Javascript
JavaScript使用百度ECharts插件绘制饼图操作示例
2019/11/26 Javascript
基于Element的组件改造的树形选择器(树形下拉框)
2020/02/27 Javascript
[01:02:07]Liquid vs Newbee 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/16 DOTA
Python时间戳使用和相互转换详解
2017/12/11 Python
python实现感知器算法(批处理)
2019/01/18 Python
Python 调用 Outlook 发送邮件过程解析
2019/08/08 Python
python中从for循环延申到推导式的具体使用
2019/11/29 Python
Python使用socket模块实现简单tcp通信
2020/08/18 Python
Stefania Mode英国:奢华设计师和时尚服装
2017/10/23 全球购物
将"引用"作为函数返回值类型的格式、好处和需要遵守的规则
2016/02/09 面试题
金鑫耀Java笔试题
2014/09/06 面试题
2014年创卫实施方案
2014/02/18 职场文书
中韩经贸翻译专业大学生职业生涯规划范文
2014/09/18 职场文书
2014年结对帮扶工作总结
2014/12/17 职场文书
服务承诺书
2015/01/19 职场文书
高一作文之暖冬
2019/11/09 职场文书
python实现的人脸识别打卡系统
2021/05/08 Python
英镑符号 £
2022/02/17 杂记