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》相關章節