collections模块主要实现了一些container datatypes(容器类型),作为builtin容器类型dict、list、set和tuple等的一个补充,包括以下新定义的容器类型:
类型 | 用途 |
---|---|
namedtuple() |
factory function for creating tuple subclasses with named fields |
deque |
双端队列,支持两端快速出入队列操作 |
ChainMap |
将多个mapping 对象组合成一个mapping对象 |
Counter |
dict subclass,用来计数hashable对象 |
OrderedDict |
dict subclass that remembers the order entries were added |
defaultdict |
dict subclass,对dict中missing的key,调用一个指定的factory function |
UserDict |
wrapper around dictionary objects for easier dict subclassing |
UserList |
wrapper around list objects for easier list subclassing |
UserString |
wrapper around string objects for easier string subclassing |
chainMap
chainMap(*maps)
用于连接多个mapping
对象称为一个mapping
,通常其速度快于使用字典的update
方法连接。其构造方法为collections.ChainMap(*maps)
,当不传入参数时,ChainMap
则会产生一个空dict;ChainMap底层用list存储mapping对象,并且可以通过.maps
属性对mapping对象进行修改,对mapping对象的修改能够即时反应到ChainMap对象;查找会依次搜索每一个mapping对象,而修改、删除、新增只会在第一个mapping对象上进行操作。
ChainMap对象除了支持所有的mapping对象方法,还有以下几个特有的属性、方法:
maps
如上所述,返回ChainMap所包装的mapping对象所组成的list,该list至少包含一个mapping对象;
new_child(m=None)
创建child context,等价于ChainMap(m, *d.maps)
,当m
为None
时,等价于ChainMap({}, *d.maps)
parents
返回parent context,即返回除了第一个mapping对象之外的所有mapping对象组成的ChainMap
对象
举个简单的例子:
>>> baseline = {'music': 'bach', 'art': 'rembrandt'}
>>> adjustments = {'art': 'van gogh', 'opera': 'carmen'}
>>> from collections import ChainMap
>>> a = ChainMap(adjustments, baseline)
>>> a['art']
'van gogh'
Counter
Counter([iterable-or-mapping])
类用于快速、方便的计数,使用频率很高的一个功能,它继承于dict
,用于计数可哈希的对象,计数的数值可以是正整数、负整数和零,实例化方法有以下几种:
>>> c = Counter() # a new, empty counter
>>> c = Counter('gallahad') # a new counter from an iterable
>>> c = Counter({'red': 4, 'blue': 2}) # a new counter from a mapping
>>> c = Counter(cats=4, dogs=8) # a new counter from keyword args
Counter
和dict
不同之处在于如果Counter
检索一个不存在的key时不会抛出KeyError
,而是返回0:
>>> c = Counter(['eggs', 'ham'])
>>> c['bacon'] # count of a missing element is zero
0
>>> del c['eggs']
除了支持父类dict
大部分的方法(不支持fromkeys(iterable)
以及update([*iterable-or-mapping*])
略有不同),还包括以下几个:
elements()
返回一个iterator
对象,每个元素重复其计数数值的次数(如果计数数值小于1,就忽略它)
>>> c = Counter(a=4, b=2, c=-1, d=-2)
>>> c.elements()
>>> list(c.elements()) # If an element’s count is less than one, elements() will ignore it.
<itertools.chain at 0x112f1be10>
['a', 'a', 'a', 'a', 'b', 'b']
most_common(n)
返回计数最大的n个元素
>>> c.most_common(2)
c.most_common(2)
>>> c.most_common()[:-3:-1] # c.most_common()[:-n-1:-1] n least common elements
subtract()
执行计数减法操作,加法可以使用update()
方法
>>> c.subtract(Counter(a=1, b=2, c=3, d=4))
>>> c
>>> c.update({'a':3}) # update([iterable-or-mapping]), 添加式的update
>>> c
Counter({'a': 3, 'b': 0, 'c': -4, 'd': -6})
Counter({'a': 6, 'b': 0, 'c': -4, 'd': -6})
Counter
还支持一些数学运算符,进行简便的运算:
>>> c = Counter(a=-3, b=5, c=4)
>>> d = Counter(a=-1, b=2, c=0)
>>> c + d # add two counters together: c[x] + d[x] (keeping only positive counts)
Counter({'b': 7, 'c': 4})
>>> c - d # subtract (keeping only positive counts)
Counter({'b': 3, 'c': 4})
>>> c & d # intersection: min(c[x], d[x]) (keeping only positive counts)
Counter({'b': 2})
>>> c | d # union: max(c[x], d[x]) (keeping only positive counts)
Counter({'b': 5, 'c': 4})
# 特殊的是,还提供两个shortcuts来表示空的Counter()加上或减去Counter对象
>>> c = Counter(a=2, b=-4)
>>> +c # 相当于 Counter() + c
Counter({'a': 2})
>>> -c # 相当于 Counter() - c
Counter({'b': 4})
deque
collections.deque([iterable[, maxlen]])
,以一个iterable对象作为参数进行初始化,得到一个双端队列。双端队列支持从任一侧线程安全,内存高效的append
和pop
操作,并且复杂度为时间O(1)。如果未指定maxlen
或为None
,则双端队列的长度可以增长到任意大小;反之,双端队列会限制为指定的最大长度。一旦限定长度的双端队列达到最大长度时,若再插入新的item,则队列另一端会自动丢弃相应数量的item。
方法和属性
append
(x)、appendleft
(x) 插入元素,前者插到队列右边,后者插入到左边extend
(iterable)、extendleft
(iterable) 插入多个元素,前者插到队列右边,后者插入到左边pop
()、popleft
() 去除并返回最左(右)边的元素clear
() 清空队列copy
() 队列浅拷贝(同copy.copy(d)
),深拷贝使用copy.deepcopy(d)
count
(x) 计数队列中与x
大小相等的元素个数index
(x[, start[, stop]]) 在[start, stop)范围内查找与x相等的第一个元素的index,如果没找到抛出ValueError
c错误insert
(i, x) 在位置i插入x,若i位置超出队列指定的最大长度,引发IndexError
remove
(value) 去除第一个与value相等的元素,若不存在引发ValueError
reverse
() in place的反转队列元素rotate
(n=1) n> 0, 队列向右移n步,反之向左移maxlen
,这是一个只读属性除了以上的属性方法, deques 还支持iteration, pickling, len(d)
, reversed(d)
, copy.copy(d)
, copy.deepcopy(d)
, in
操作符 以及索引操作,如d[-1]. 索引队列两边的元素复杂度都是O(1),当索引获取中间的元素复杂度会是O(n), 因此涉及大量中间元素索引操作的场景应该使用list。
应用举例
比如获取一个文件的后N行可以采用以下方式:
def tail(filename, n=10):
with open(filename) as f:
return deque(f, n)
defaultdict
关于defaultdict
,我们可以先看一下dict
中一个类似功能的函数setdefault(k, d=None)
:
d = {}
s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
for k, v in s:
d.setdefault(k, []).append(v)
sorted(d.items())
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
在上述代码中,setdefault(k, d=[])
一句话相当于做了两件事情:一是获取key为k的的value,二是若该key不存在则设置其值为[]
。即,d.get(k, [])以及如果key不存在就设置d[k] = []。现在再回到defaultdict
,defaultdict([default_factory[, ...]])
,构造方法中default_factory
默认是None
,defaultdict
是dict
的一个subclass,它重写了一个__miss__
方法以及拥有一个default_factory
属性。
__miss__(key)
该方法在当key不存在时才会且仅被__getitem__()
调用,所以当使用dict.get()
方法获取一个不存在的键值时,返回结果为None
,而不是使用default_factory
;
当default_factory
为None
时,索引一个不存在的key
会引发KeyError
异常;
当default_factory
不为None
时,索引一个不存在的key
则使用default_factory
进行初始化并返回值
>>> from collections import defaultdict
>>> d2 = defaultdict(int ,a=1, b=2)
>>> d2['c']
0
>>> d2 = defaultdict(int ,a=1, b=2)
>>> d2.get('c')
None
>>> d2
defaultdict(int, {'a': 1, 'b': 2})
>>> d1 = defaultdict(a=1, b=2)
>>> d1['c']
KeyError: 'c'
default_factory
该属性在上述__miss__()
函数中使用,由构造函数中的default_factory
初始化,默认为None
因此,上述例子可以使用defaultdict来实现如下:
s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
d = defaultdict(list)
for k, v in s:
d[k].append(v)
sorted(d.items())
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
namedtuple
namedtuple
用来构造带字段名的元组。namedtuple
的实例和普通元组消耗的内存一样多,因为字段名都被存在对应的类里面。这个类跟普通的对象实例比起来也要小一些,因为 Python 不会用 __dict__
来存放这些实例的属性。它们可以在使用常规tuple的任何地方使用,并且它们还具有按名称(tuple只能按index)访问字段的能力。其构造函数为:collections.namedtuple(typename, field_names,*, rename=False, defaults=None, module=None)
,简单例子如下:
>>> # Basic example
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(11, y=22) # instantiate with positional or keyword arguments
>>> p[0] + p[1] # indexable like the plain tuple (11, 22)
33
>>> x, y = p # unpack like a regular tuple
>>> x, y
(11, 22)
>>> p.x + p.y # fields also accessible by name
33
>>> p # readable __repr__ with a name=value style
Point(x=11, y=22)
OrderedDict
OrderedDict
和一般的dict
类似,但是还具有记忆字典中存储的key的插入顺序。但是现在OrderDict
可能用处不大了,因为从Python 3.7开始,一般的dict
也具有这个特性。但是,dict
和OrderedDict
依旧有些区别:
dict
,最重要的高效的mapping operations,而Track 插入顺序是次要的;OrderedDict
,最重要的是排序操作,而空间效率、迭代效率以及更新字典的性能是次要的;OrderedDict
可以处理频繁的需要重排的操作,适合于Track最近的操作;OrderedDict
是否相等同时要求顺序也相同;OrderedDict
的popitem(last=True)
中可以通过last参数控制pop哪一端的元素;OrderedDict
的move_to_end(key, last=True)
可以高效的将元素移至末尾;dict
没有__reversed__()
方法;UserDict
& UserList
& UserString
UserDict
& UserList
& UserString
分别是dict
、list
、str
的一个wrapper,在实际应用中,已经很少使用到它们了,因为我们可以直接方便的继承它们,自定义对应的子类,稍微了解一下即可,下面给出一个简单的例子: