这个模块实现了特定目标的容器,以提供Python标准内建容器 dict、list、set、tuple 的替代选择。
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
是内置 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 "" , 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
>>> nums = collections.defaultdict(dict)
>>> nums[1] = {
'one':1}
>>> nums
defaultdict(<class 'dict'>, {
1: {
'one': 1}})
>>> nums[2]
{
}
>>> nums
defaultdict(<class 'dict'>, {
1: {
'one': 1}, 2: {
}})
使用 set
作为 default_factory
>>> types = collections.defaultdict(set)
>>> types['手机'].add('华为')
>>> types['手机'].add('小米')
>>> types['显示器'].add('AOC')
>>> types
defaultdict(<class 'set'>, {
'手机': {
'华为', '小米'}, '显示器': {
'AOC'}})
Python字典中的键的顺序是任意的,它们不受添加的顺序的控制。
collections.OrderedDict
类提供了保留他们添加顺序的字典对象
>>> o = collections.OrderedDict()
>>> o['k1'] = 'v1'
>>> o['k3'] = 'v3'
>>> o['k2'] = 'v2'
>>> o
OrderedDict([('k1', 'v1'), ('k3', 'v3'), ('k2', 'v2')])
如果在已经存在的 key 上添加新的值,将会保留原来的 key 的位置,然后覆盖 value 值。
>>> o['k1'] = 666
>>> o
OrderedDict([('k1', 666), ('k3', 'v3'), ('k2', 'v2')])
>>> dict(o)
{
'k1': 666, 'k3': 'v3', 'k2': 'v2'}
三种定义命名元组的方法:第一个参数是命名元组的构造器(如下的:Person1,Person2,Person3)
>>> P1 = collections.namedtuple('Person1',['name','age','height'])
>>> P2 = collections.namedtuple('Person2','name,age,height')
>>> P3 = collections.namedtuple('Person3','name age height')
实例化命名元组
>>> 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
collections.deque
返回一个新的双向队列对象,从左到右初始化(用方法 append()),从 iterable(迭代对象)数据创建。如果 iterable 没有指定,新队列为空。
collections.deque
队列支持线程安全,对于从两端添加(append)或者弹出(pop),复杂度O(1)。
虽然 list
对象也支持类似操作,但是这里优化了定长操作(pop(0)、insert(0,v))的开销。
如果 maxlen 没有指定或者是 None ,deque 可以增长到任意长度。否则,deque 就限定到指定最大长度。一旦限定长度的 deque 满了,当新项加入时,同样数量的项就从另一端弹出。
支持的方法:
>>> 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)
问题背景是我们有多个字典或者映射,想把它们合并成为一个单独的映射,有人说可以用update进行合并,这样做的问题就是新建了一个数据结构以致于当我们对原来的字典进行更改的时候不会同步。如果想建立一个同步的查询方法,可以使用 ChainMap
可以用来合并两个或者更多个字典,当查询的时候,从前往后依次查询。简单使用:
>>> 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
有一个注意点就是当对ChainMap进行修改的时候总是只会对第一个字典进行修改,如果第一个字典不存在该键,会添加。
>>> 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 是去掉了列表开头的元素
>>> 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({
})