写在之前

我们都知道 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的资料请关注其它相关文章!

华山资源网 Design By www.eoogi.com
广告合作:本站广告合作请联系QQ:858582 申请时备注:广告合作(否则不回)
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
华山资源网 Design By www.eoogi.com

稳了!魔兽国服回归的3条重磅消息!官宣时间再确认!

昨天有一位朋友在大神群里分享,自己亚服账号被封号之后居然弹出了国服的封号信息对话框。

这里面让他访问的是一个国服的战网网址,com.cn和后面的zh都非常明白地表明这就是国服战网。

而他在复制这个网址并且进行登录之后,确实是网易的网址,也就是我们熟悉的停服之后国服发布的暴雪游戏产品运营到期开放退款的说明。这是一件比较奇怪的事情,因为以前都没有出现这样的情况,现在突然提示跳转到国服战网的网址,是不是说明了简体中文客户端已经开始进行更新了呢?