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)
可以高效的將元素移至末尾;- 直到Python3.8,
dict
沒有__reversed__()
方法;
UserDict
& UserList
& UserString
UserDict
& UserList
& UserString
分別是dict
、list
、str
的一個wrapper,在實際應用中,已經很少使用到它們了,因爲我們可以直接方便的繼承它們,自定義對應的子類,稍微瞭解一下即可,下面給出一個簡單的例子: