国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

Python標準庫之collections包的使用教程

2019-11-25 16:13:17
字體:
來源:轉載
供稿:網友

前言

Python為我們提供了4種基本的數據結構:list, tuple, dict, set,但是在處理數據量較大的情形的時候,這4種數據結構就明顯過于單一了,比如list作為數組在某些情形插入的效率會比較低,有時候我們也需要維護一個有序的dict。所以這個時候我們就要用到Python標準庫為我們提供的collections包了,它提供了多個有用的集合類,熟練掌握這些集合類,不僅可以讓我們讓寫出的代碼更加Pythonic,也可以提高我們程序的運行效率。

defaultdict

defaultdict(default_factory)在普通的dict之上添加了default_factory,使得key不存在時會自動生成相應類型的value,default_factory參數可以指定成list, set, int等各種合法類型。

我們現在有下面這樣一組list,雖然我們有5組數據,但是仔細觀察后發現其實我們只有3種color,但是每一種color對應多個值。現在我們想要將這個list轉換成一個dict,這個dict的key對應一種color,dict的value設置為一個list存放color對應的多個值。我們可以使用defaultdict(list)來解決這個問題。

>>> from collections import 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])]

以上等價于:

>>> d = {}>>> for k, v in s:...  d.setdefault(k, []).append(v)...>>> sorted(d.items())[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]

如果我們不希望含有重復的元素,可以考慮使用defaultdict(set) 。set相比list的不同之處在于set中不允許存在相同的元素。

>>> from collections import defaultdict>>> s = [('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue', 4)]>>> d = defaultdict(set)>>> for k, v in s:...  d[k].add(v)...>>> sorted(d.items())[('blue', {2, 4}), ('red', {1, 3})]

OrderedDict

Python3.6之前的dict是無序的,但是在某些情形我們需要保持dict的有序性,這個時候可以使用OrderedDict,它是dict的一個subclass,但是在dict的基礎上保持了dict的有序型,下面我們來看一下使用方法。

>>> # regular unsorted dictionary>>> d = {'banana': 3, 'apple': 4, 'pear': 1, 'orange': 2}>>> # dictionary sorted by key>>> OrderedDict(sorted(d.items(), key=lambda t: t[0]))OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])>>> # dictionary sorted by value>>> OrderedDict(sorted(d.items(), key=lambda t: t[1]))OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])>>> # dictionary sorted by length of the key string>>> OrderedDict(sorted(d.items(), key=lambda t: len(t[0])))OrderedDict([('pear', 1), ('apple', 4), ('orange', 2), ('banana', 3)])

使用popitem(last=True)方法可以讓我們按照LIFO(先進后出)的順序刪除dict中的key-value,即刪除最后一個插入的鍵值對,如果last=False就按照FIFO(先進先出)刪除dict中key-value。

>>> d = {'banana': 3, 'apple': 4, 'pear': 1, 'orange': 2}>>> # dictionary sorted by key>>> d = OrderedDict(sorted(d.items(), key=lambda t: t[0]))>>> dOrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])>>> d.popitem()('pear', 1)>>> d.popitem(last=False)('apple', 4)

使用move_to_end(key, last=True)來改變有序的OrderedDict對象的key-value順序,通過這個方法我們可以將排序好的OrderedDict對象中的任意一個key-value插入到字典的開頭或者結尾。

>>> d = OrderedDict.fromkeys('abcde')>>> dOrderedDict([('a', None), ('b', None), ('c', None), ('d', None), ('e', None)])>>> d.move_to_end('b')>>> dOrderedDict([('a', None), ('c', None), ('d', None), ('e', None), ('b', None)])>>> ''.join(d.keys())'acdeb'>>> d.move_to_end('b', last=False)>>> ''.join(d.keys())'bacde'

deque

list存儲數據的優勢在于按索引查找元素會很快,但是插入和刪除元素就很慢了,因為list是基于數組實現的。deque是為了高效實現插入和刪除操作的雙向列表,適合用于隊列和棧,而且線程安全。

list只提供了append和pop方法來從list的尾部插入/刪除元素,deque新增了appendleft/popleft等方法允許我們高效的在元素的開頭來插入/刪除元素。而且使用deque在隊列兩端append或pop元素的算法復雜度大約是O(1),但是對于list對象改變列表長度和數據位置的操作例如 pop(0)insert(0, v)操作的復雜度高達O(n)。

>>> from collections import deque>>> dq = deque(range(10), maxlen=10)>>> dqdeque([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)>>> dq.rotate(3)>>> dqdeque([7, 8, 9, 0, 1, 2, 3, 4, 5, 6], maxlen=10)>>> dq.rotate(-4)>>> dqdeque([1, 2, 3, 4, 5, 6, 7, 8, 9, 0], maxlen=10)>>> dq.appendleft(-1)>>> dqdeque([-1, 1, 2, 3, 4, 5, 6, 7, 8, 9], maxlen=10)>>> dq.extend([11, 22, 33])>>> dqdeque([3, 4, 5, 6, 7, 8, 9, 11, 22, 33], maxlen=10)>>> dq.extendleft([10, 20, 30, 40])>>> dqdeque([40, 30, 20, 10, 3, 4, 5, 6, 7, 8], maxlen=10)

Counter

Count用來統計相關元素的出現次數。

>>> from collections import Counter>>> ct = Counter('abracadabra')>>> ctCounter({'a': 5, 'r': 2, 'b': 2, 'd': 1, 'c': 1})>>> ct.update('aaaaazzz')>>> ctCounter({'a': 10, 'z': 3, 'r': 2, 'b': 2, 'd': 1, 'c': 1})>>> ct.most_common(2)[('a', 10), ('z', 3)]>>> ct.elements()<itertools.chain object at 0x7fbaad4b44e0>

namedtuple

使用namedtuple(typename, field_names)命名tuple中的元素來使程序更具可讀性。

>>> from collections import namedtuple>>> City = namedtuple('City', 'name country population coordinates')>>> tokyo = City('Tokyo', 'JP', 36.933, (35.689722, 139.691667))>>> tokyoCity(name='Tokyo', country='JP', population=36.933, coordinates=(35.689722, 139.691667))>>> tokyo.population36.933>>> tokyo.coordinates(35.689722, 139.691667)>>> tokyo[1]'JP'
>>> City._fields('name', 'country', 'population', 'coordinates')>>> LatLong = namedtuple('LatLong', 'lat long')>>> delhi_data = ('Delhi NCR', 'IN', 21.935, LatLong(28.613889, 77.208889))>>> delhi = City._make(delhi_data)>>> delhi._asdict()OrderedDict([('name', 'Delhi NCR'), ('country', 'IN'), ('population', 21.935),   ('coordinates', LatLong(lat=28.613889, long=77.208889))])>>> for key, value in delhi._asdict().items():  print(key + ':', value)name: Delhi NCRcountry: INpopulation: 21.935coordinates: LatLong(lat=28.613889, long=77.208889)

ChainMap

ChainMap可以用來合并多個字典。

>>> from collections import ChainMap>>> d = ChainMap({'zebra': 'black'}, {'elephant': 'blue'}, {'lion': 'yellow'})>>> d['lion'] = 'orange'>>> d['snake'] = 'red'>>> dChainMap({'lion': 'orange', 'zebra': 'black', 'snake': 'red'},   {'elephant': 'blue'}, {'lion': 'yellow'})
>>> del d['lion']>>> del d['elephant']Traceback (most recent call last): File "/usr/lib/python3.5/collections/__init__.py", line 929, in __delitem__ del self.maps[0][key]KeyError: 'elephant'During handling of the above exception, another exception occurred:Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib/python3.5/collections/__init__.py", line 931, in __delitem__ raise KeyError('Key not found in the first mapping: {!r}'.format(key))KeyError: "Key not found in the first mapping: 'elephant'"

從上面del['elephant']的報錯信息可以看出來,對于改變鍵值的操作ChainMap只會在第一個字典self.maps[0][key]進行查找,新增加的鍵值對也都會加入第一個字典,我們來改進一下ChainMap解決這個問題:

class DeepChainMap(ChainMap): 'Variant of ChainMap that allows direct updates to inner scopes' def __setitem__(self, key, value):  for mapping in self.maps:   if key in mapping:    mapping[key] = value    return  self.maps[0][key] = value def __delitem__(self, key):  for mapping in self.maps:   if key in mapping:    del mapping[key]    return  raise KeyError(key)>>> d = DeepChainMap({'zebra': 'black'}, {'elephant': 'blue'}, {'lion': 'yellow'})>>> d['lion'] = 'orange'   # update an existing key two levels down>>> d['snake'] = 'red'   # new keys get added to the topmost dict>>> del d['elephant']   # remove an existing key one level downDeepChainMap({'zebra': 'black', 'snake': 'red'}, {}, {'lion': 'orange'})

可以使用new_child來deepcopy一個ChainMap:

>>> from collections import ChainMap>>> a = {'a': 'A', 'c': 'C'}>>> b = {'b': 'B', 'c': 'D'}>>> m = ChainMap({'a': 'A', 'c': 'C'}, {'b': 'B', 'c': 'D'})>>> mChainMap({'a': 'A', 'c': 'C'}, {'b': 'B', 'c': 'D'})>>> m['c']'C'>>> m.maps[{'c': 'C', 'a': 'A'}, {'c': 'D', 'b': 'B'}]>>> a['c'] = 'E'>>> m['c']'E'>>> mChainMap({'c': 'E', 'a': 'A'}, {'c': 'D', 'b': 'B'})
>>> m2 = m.new_child()>>> m2['c'] = 'f'>>> m2ChainMap({'c': 'f'}, {'c': 'E', 'a': 'A'}, {'c': 'D', 'b': 'B'})>>> mChainMap({'c': 'E', 'a': 'A'}, {'c': 'D', 'b': 'B'})>>> m2.parentsChainMap({'c': 'E', 'a': 'A'}, {'c': 'D', 'b': 'B'})

UserDict

下面我們來改進一下字典,查詢字典的時候將key轉換為str的形式:

class StrKeyDict0(dict): def __missing__(self, key):  if isinstance(key, str):   raise KeyError(key)  return self[str(key)] def get(self, key, default=None):  try:   return self[key]  except KeyError:   return default def __contains__(self, key):  return key in self.keys() or str(key) in self.keys()

解釋一下上面這段程序:

  • 在__missing__中isinstance(key, str)是必須要的,請思考一下為什么? 因為假設一個key不存在的話,這會造成infinite recursion,self[str(key)]會再次調用__getitem__。
  • __contains__也是必須實現的,因為k in d的時候會進行調用,但是注意即使查找失敗它也不會調用__missing__。關于__contains__還有一個細節就是:我們并沒有使用k in my_dict,因為str(key) in self的形式,因為這會造成遞歸調用__contains__。

這里還強調一點,在Python2.x中dict.keys()會返回一個list,這意味著k in my_list必須遍歷list。在Python3.x中針對dict.keys()做了優化,性能更高,它會返回一個view如同set一樣,詳情參考官方文檔

上面這個例子可以用UserDict改寫,并且將所有的key都以str的形式存儲,而且這種寫法更加常用簡潔:

import collectionsclass StrKeyDict(collections.UserDict): def __missing__(self, key):  if isinstance(key, str):   raise KeyError(key)  return self[str(key)] def __contains__(self, key):  return str(key) in self.data def __setitem__(self, key, item):  self.data[str(key)] = item

UserDict是MutableMapping和Mapping的子類,它繼承了MutableMapping.update和Mapping.get兩個重要的方法,所以上面我們并沒有重寫get方法,可以在源碼中看到它的實現和我們上面的實現是差不多的。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對武林網的支持。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 鸡东县| 赣州市| 延津县| 惠来县| 怀宁县| 永善县| 嘉兴市| 渝北区| 犍为县| 贵定县| 会同县| 抚顺市| 弥渡县| 松江区| 平凉市| 光泽县| 桐城市| 禹州市| 孙吴县| 炎陵县| 固阳县| 区。| 普格县| 双桥区| 合水县| 祁东县| 称多县| 当涂县| 宿迁市| 三江| 孝义市| 遂宁市| 兴海县| 南丰县| 突泉县| 五大连池市| 成都市| 卢湾区| 宁陕县| 汉寿县| 黄龙县|