collections.namedtuple
是一个工厂函数,它能够用来构建一个带字段名的元组和一个有名字的类——这个带名字的类对调试程序有很大帮助。php
咱们能够这样建立一个 User 类:html
Card = collections.namedtuple('User', ['name', 'age', 'height'])
复制代码
如何用具名元组来记录一个城市的信息java
In [1]: from collections import namedtuple
In [2]: City = namedtuple('City', 'name country population coordinates')
In [3]: tokyo = City('Tokyo', 'JP', 36.933, (35.689722, 139.691667))
In [4]: tokyo
Out[4]: City(name='Tokyo', country='JP', population=36.933, coordinates=(35.689722, 139.691667))
In [5]: tokyo.population
Out[5]: 36.933
In [6]: tokyo.coordinates
Out[6]: (35.689722, 139.691667)
In [7]: tokyo[1]
Out[7]: 'JP'
复制代码
建立一个具名元组须要两个参数,一个是类名,另外一个是类的各个字段的名字。后者能够是由数个字符串组成的可迭代对象,或者是由空格分隔开的字段名组成的字符串。python
除了从普通元组那里继承来的属性以外,具名元组还有一些本身专有的属性。c++
In [8]: City._fields
Out[8]: ('name', 'country', 'population', 'coordinates')
In [9]: LatLong = namedtuple('LatLong', 'lat long')
In [10]: delhi_data = ('Delhi NCR', 'IN', 21.935, LatLong(28.613889, 77.208889))
In [11]: delhi = City._make(delhi_data)
In [12]: delhi._asdict()
Out[12]:
OrderedDict([('name', 'Delhi NCR'),
('country', 'IN'),
('population', 21.935),
('coordinates', LatLong(lat=28.613889, long=77.208889))])
In [13]: for key, value in delhi._asdict().items():
...: print(key + ':', value)
...:
name: Delhi NCR
country: IN
population: 21.935
coordinates: LatLong(lat=28.613889, long=77.208889)
复制代码
_fields
属性是一个包含这个类全部字段名称的元组。swift
用 _make()
经过接受一个可迭代对象来生成这个类的一个实例,它的做用跟 City(*delhi_data)
是同样的。安全
_asdict()
把具名元组以 collections.OrderedDict
的形式返回,咱们能够利用它来把元组里的信息友好地呈现出来。app
首先咱们看一个例子。函数
用 dict 统计一个 list 中字符串出现的次数:spa
In [1]: langs = ['java', 'php', 'python', 'C#', 'kotlin', 'swift', 'python']
In [2]: res_dict = {}
In [3]: for lang in langs:
...: if lang in res_dict:
...: res_dict[lang] += 1
...: else:
...: res_dict[lang] = 1
...:
In [4]: res_dict
Out[4]: {'C#': 1, 'java': 1, 'kotlin': 1, 'php': 1, 'python': 2, 'swift': 1}
复制代码
这里每次循环都要判断一次,能够调用 setdefault
方法来消除判断。
In [1]: langs = ['java', 'php', 'python', 'C#', 'kotlin', 'swift', 'python']
In [2]: res_dict = {}
In [3]: for lang in langs:
...: res_dict.setdefault(lang, 0)
...: res_dict[lang] += 1
...:
In [4]: res_dict
Out[4]: {'C#': 1, 'java': 1, 'kotlin': 1, 'php': 1, 'python': 2, 'swift': 1}
复制代码
可是如今还有一个错误,每次取值使还要进行一次判断,不然若是值不存在就会抛异常:
In [5]: res_dict['c++']
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-5-269671e9ed5a> in <module>()
----> 1 res_dict['c++']
KeyError: 'c++'
复制代码
有时候为了方便起见,就算某个键在映射里不存在,咱们也但愿在经过这个键读取值的时候能获得一个默认值。有两个途径能帮咱们达到这个目的,一个是经过 defaultdict
这个类型而不是普通的 dict
,另外一个是给本身定义一个 dict
的子类,而后在子类中实现 __missing__
方法。
In [7]: from collections import defaultdict
In [8]: res_dict= defaultdict(int)
In [9]: for lang in langs:
...: res_dict[lang] += 1
...:
In [10]: res_dict
Out[10]:
defaultdict(int,
{'C#': 1,
'java': 1,
'kotlin': 1,
'php': 1,
'python': 2,
'swift': 1})
In [11]: res_dict['c++']
Out[11]: 0
复制代码
这样就完美解决了上述全部问题, defaultdict
构造函数接收一个可调用的对象,当 __getitem__
方法找不到值的时候就会调用该对象返回一个值。
因此咱们能够返回更复杂的默认值:
In [25]: def gen_dict():
...: return {'name': 'None', 'age': 0}
...:
In [26]: res_dict = defaultdict(gen_dict)
In [27]: res_dict['zhangsan']
Out[27]: {'age': 0, 'name': 'None'}
复制代码
__missing__
方法In [28]: class CustomDict(dict):
...:
...: def __missing__(self, key):
...: return {'name': 'None', 'age': 18}
...:
In [29]: res_dict = CustomDict()
In [30]: res_dict['lisi']
Out[30]: {'age': 18, 'name': 'None'}
复制代码
collections.deque
类(双向队列)是一个线程安全、能够快速从两端添加或者删除元素的数据类型。并且若是想要有一种数据类型来存放“最近用到的几个元素”,deque 也是一个很好的选择。这是由于在新建一个双向队列的时候,你能够指定这个队列的大小,若是这个队列满员了,还能够从反向端删除过时的元素,而后在尾端添加新的元素。
In [1]: from collections import deque
In [2]: dq = deque(range(10), maxlen=10)
In [3]: dq
Out[3]: deque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [4]: dq.rotate(3)
In [5]: dq
Out[5]: deque([7, 8, 9, 0, 1, 2, 3, 4, 5, 6])
In [6]: dq.rotate(-4)
In [7]: dq
Out[7]: deque([1, 2, 3, 4, 5, 6, 7, 8, 9, 0])
In [8]: dq.appendleft(-1)
In [9]: dq
Out[9]: deque([-1, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [10]: dq.extend([11, 22, 33])
In [11]: dq
Out[11]: deque([3, 4, 5, 6, 7, 8, 9, 11, 22, 33])
In [12]: dq.extendleft([10, 20, 30, 40])
In [13]: dq
Out[13]: deque([40, 30, 20, 10, 3, 4, 5, 6, 7, 8])
复制代码
maxlen
是一个可选参数,表明这个队列能够容纳的元素的数量,并且一旦设定,这个属性就不能修改了。
队列的旋转操做 (rotate
) 接受一个参数 n,当 n > 0 时,队列的最右边的 n 个元素会被移动到队列的左边。当 n < 0 时,最左边的 n 个元素会被移动到右边。
当试图对一个已满(len(d) == d.maxlen)的队列作尾部添加操做的时候,它头部的元素会被删除掉。
extendleft(iter)
方法会把迭代器里的元素逐个添加到双向队列的左边,所以迭代器里的元素会逆序出如今队列里。
这个映射类型会给键准备一个整数计数器。每次更新一个键的时候都会增长这个计数器。因此这个类型能够用来给可散列表对象计数,或者是当成多重集来用——多重集合就是集合里的元素能够出现不止一次。Counter 实现了 + 和 - 运算符用来合并记录,还有像 most_common([n]) 这类颇有用的方法。most_common([n]) 会按照次序返回映射里最多见的 n 个键和它们的计数
In [1]: from collections import Counter
In [2]: langs = ['java', 'php', 'python', 'C#', 'kotlin', 'swift', 'python']
In [3]: ct = Counter(langs)
In [4]: ct
Out[4]: Counter({'C#': 1, 'java': 1, 'kotlin': 1, 'php': 1, 'python': 2, 'swift': 1})
In [5]: ct.update(['java', 'c'])
In [6]: ct
Out[6]:
Counter({'C#': 1,
'c': 1,
'java': 2,
'kotlin': 1,
'php': 1,
'python': 2,
'swift': 1})
In [7]: ct.most_common(2)
Out[7]: [('java', 2), ('python', 2)]
复制代码
固然,也能够直接操做字符串:
In [9]: ct = Counter('abracadabra')
In [10]: ct
Out[10]: Counter({'a': 5, 'b': 2, 'c': 1, 'd': 1, 'r': 2})
In [11]: ct.update('aaaaazzz')
In [12]: ct
Out[12]: Counter({'a': 10, 'b': 2, 'c': 1, 'd': 1, 'r': 2, 'z': 3})
In [13]: ct.most_common(2)
Out[13]: [('a', 10), ('z', 3)]
复制代码
这个类型在添加键的时候会保持顺序,所以键的迭代次序老是一致的。OrderedDict 的 popitem 方法默认删除并返回的是字典里的最后一个元素,可是若是像 my_odict.popitem(last=False)
这样调用它,那么它删除并返回第一个被添加进去的元素。
move_to_end(key, last=True)
将现有 key 移至有序字典的末尾。若是 last=True
(默认),则 item 移动到右侧,若是 last=False
,则移动到开始。若是 key 不存在,则引起 KeyError
:
In [1]: from collections import OrderedDict
In [2]: d = OrderedDict.fromkeys('abcde')
In [3]: d.move_to_end('b')
In [4]: ''.join(d.keys())
Out[4]: 'acdeb'
In [5]: d.move_to_end('b', last=False)
In [6]: ''.join(d.keys())
Out[6]: 'bacde'
复制代码
因为 OrderedDict 会记住它的插入顺序,所以它能够与 sorted 结合使用来建立一个排序后的字典:
In [11]: d = {'banana': 3, 'apple': 4, 'pear': 1, 'orange': 2}
# 根据 key 排序
In [12]: OrderedDict(sorted(d.items(), key=lambda t:t[0]))
Out[12]: OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])
# 根据 value 排序
In [13]: OrderedDict(sorted(d.items(), key=lambda t:t[1]))
Out[13]: OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])
# 根据 key 的长度排序
In [14]: OrderedDict(sorted(d.items(), key=lambda t: len(t[0])))
Out[14]: OrderedDict([('pear', 1), ('apple', 4), ('banana', 3), ('orange', 2)])
复制代码
删除条目时,新排序的字典会保持排序顺序。可是,当添加新的 key 时,key 被追加到最后,并不保持排序。
ChainMap
类提供用于快速连接多个 dict,以便将它们视为单个单元。它一般比建立新 dict 和运行多个 update()
调用要快得多。
In [1]: from collections import ChainMap
In [2]: d1 = {'java': 3, 'python': 4}
In [3]: d2 = {'c++': 1, 'java': 2}
In [4]: for key, val in ChainMap(d1, d2).items():
...: print(key, val)
...:
c++ 1
java 3
python 4
复制代码
后出现的重复的 key 将被忽略
ChainMap
将连接的 dict 存储在一个列表中。该列表是公开的,可使用 maps
属性进行访问或更新。
In [10]: c1 = ChainMap(d1, d2)
In [11]: c1.maps[0]
Out[11]: {'java': 3, 'python': 4}
In [12]: c1.maps[0]['python'] = 2
In [13]: c1.items()
Out[13]: ItemsView(ChainMap({'java': 3, 'python': 2}, {'c++': 1, 'java': 2}))
In [14]: dict(c1)
Out[14]: {'c++': 1, 'java': 3, 'python': 2}
复制代码
python必学模块-collections
8.3. collections — Container datatypes 《流畅的 Python》相关章节