详解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编写一个简单的tic-tac-toe游戏的教程
Apr 16 Python
Python算法应用实战之队列详解
Feb 04 Python
Python3利用SMTP协议发送E-mail电子邮件的方法
Sep 30 Python
Matplotlib 生成不同大小的subplots实例
May 25 Python
更换Django默认的模板引擎为jinja2的实现方法
May 28 Python
Python基于最小二乘法实现曲线拟合示例
Jun 14 Python
Python Series从0开始索引的方法
Nov 06 Python
Python实现的爬取小说爬虫功能示例
Mar 30 Python
python numpy数组中的复制知识解析
Feb 03 Python
Python sep参数使用方法详解
Feb 12 Python
使用Pycharm分段执行代码
Apr 15 Python
python基于pexpect库自动获取日志信息
Feb 01 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 mysql索引问题
2008/06/07 PHP
javascript+php实现根据用户时区显示当地时间的方法
2015/03/11 PHP
PHP爬虫之百万级别知乎用户数据爬取与分析
2016/01/22 PHP
PHP获取文件扩展名的方法实例总结
2017/06/10 PHP
window.location.reload()方法刷新页面弹出要再次显示该网页对话框
2013/04/24 Javascript
Jquery 跨域访问 Lightswitch OData Service的方法
2013/09/11 Javascript
JS实现闪动的title消息提醒效果
2014/06/20 Javascript
jQuery使用之设置元素样式用法实例
2015/01/19 Javascript
浅谈javascript事件取消和阻止冒泡
2015/05/26 Javascript
js实现继承的5种方式
2015/12/01 Javascript
js实现千分符和保留几位小数的简单实例
2016/08/01 Javascript
用jQuery的AJax实现异步访问、异步加载
2016/11/02 Javascript
javascript实现简单的可随机变色网页计算器示例
2016/12/30 Javascript
vue2滚动条加载更多数据实现代码
2017/01/10 Javascript
使用vue.js2.0 + ElementUI开发后台管理系统详细教程(一)
2017/01/21 Javascript
利用javascript实现的三种图片放大镜效果实例(附源码)
2017/01/23 Javascript
js for终止循环 跳出多层循环
2018/10/04 Javascript
angular中如何绑定iframe中src的方法
2019/02/01 Javascript
优雅地使用loading(推荐)
2019/04/20 Javascript
[03:37]2015国际邀请赛第四日现场精彩集锦
2015/08/08 DOTA
[03:56]DOTA2完美大师赛趣味视频之小鸽子和Mineski打台球
2017/11/24 DOTA
Google开源的Python格式化工具YAPF的安装和使用教程
2016/05/31 Python
Python实现将一个正整数分解质因数的方法分析
2017/12/14 Python
HTML5 CSS3实现一个精美VCD包装盒个性幻灯片案例
2014/06/16 HTML / CSS
Skyscanner澳大利亚:全球领先的旅游搜索网站
2018/03/24 全球购物
应届生求职简历的自我评价怎么写
2013/10/23 职场文书
证婚人经典证婚词
2014/01/09 职场文书
王兆力在市委党的群众路线教育实践活动总结大会上的讲话稿
2014/10/25 职场文书
2015会计试用期工作总结
2014/12/12 职场文书
2015年城管个人工作总结范文
2015/04/20 职场文书
2015年度高中教师工作总结
2015/05/26 职场文书
雨雪天气温馨提示
2015/07/15 职场文书
医院消毒隔离制度
2015/08/05 职场文书
七年级写作指导之游记作文
2019/10/07 职场文书
html实现弹窗的实例
2021/06/09 HTML / CSS
电频谱管理的原则是什么
2022/02/18 无线电