天天看點

python︱ collections子產品(namedtuple/defaultdict/OrderedDict等)1 namedtuple - 可命名的tuple2 deque - 高效有序的list3 defaultdict - 防dict報錯4 OrderedDict - 有序的dict5 ChainMap - dict合并6 Counter - 計數參考:

collections有的功能:

['deque', 'defaultdict', 'namedtuple',  'UserDict', 'UserList', 'UserString',\
 'Counter', 'OrderedDict', 'ChainMap', 'Awaitable', 'Coroutine', 'AsyncIterable', \
 'AsyncIterator', 'AsyncGenerator', 'Hashable',  'Iterable', 'Iterator', 'Generator', 'Reversible', \
 'Sized', 'Container', 'Callable', 'Collection', 'Set', 'MutableSet', 'Mapping', 'MutableMapping', \
 'MappingView', 'KeysView', 'ItemsView', 'ValuesView', 'Sequence', 'MutableSequence', 'ByteString']           

複制

高效/便捷。

官方:python - collections

文章目錄

  • 1 namedtuple - 可命名的tuple
    • 1.1 namedtuple 建立
    • 1.2 namedtuple支援通過屬性通路
    • 1.3 namedtuple轉OrderedDict
    • 1.4 其他一些屬性
    • 1.5 實踐的例子
  • 2 deque - 高效有序的list
  • 3 defaultdict - 防dict報錯
    • 情況一:報錯傳回預設值
    • 情況二:未定義key,一鍵定義
  • 4 OrderedDict - 有序的dict
  • 5 ChainMap - dict合并
  • 6 Counter - 計數
  • 參考:

1 namedtuple - 可命名的tuple

>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(1, 2)
>>> p.x
1
>>> p.y
2           

複制

給[‘x’,‘y’]這個tuple命名為

point

,這個tuple中,第一個空位命名為

'x'

,第二個為

'y'

>>> isinstance(p, Point)
True
>>> isinstance(p, tuple)
True           

複制

1.1 namedtuple 建立

from collections import namedtuple

Animal = namedtuple('Animal', 'name age type')
perry = Animal(name="perry", age=31, type="cat")

print(perry)
## 輸出: Animal(name='perry', age=31, type='cat')

print(perry.name)
## 輸出: 'perry'

print(perry[0])
## 輸出: perry           

複制

在上面的例子中,我們的元組名稱是Animal,字段名稱是’name’,‘age’和’type’。

要記住它是一個元組,屬性值在namedtuple中是不可變的,是以下面的代碼不能工作:

from collections import namedtuple

Animal = namedtuple('Animal', 'name age type')
perry = Animal(name="perry", age=31, type="cat")
perry.age = 42

## 輸出:
## Traceback (most recent call last):
##     File "", line 1, in
## AttributeError: can't set attribute           

複制

1.2 namedtuple支援通過屬性通路

namedtuple既支援tupleindex的通路方式,也支援通過屬性通路

>>> p[0] + p[1] 
33
>>> x, y = p
>>> x, y 
(11, 22)
>>> p.x + p.y
33           

複制

namedtuple和dict的互轉,嚴格說是與OrderedDict互轉,因為_asdict傳回的是一個OrderedDict

>>> d = p._asdict() 
OrderedDict([('x', 11), ('y', 22)])           

複制

1.3 namedtuple轉OrderedDict

from collections import namedtuple

Animal = namedtuple('Animal', 'name age type')
perry = Animal(name="Perry", age=31, type="cat")
print(perry._asdict())

## 輸出: OrderedDict([('name', 'Perry'), ('age', 31), ...           

複制

1.4 其他一些屬性

>>> p2._replace(y=100)    # 替換元素值
Point(x=11, y=100, z=33)
>>> p._fields             # 檢視對象字段
('x', 'y', 'z')
>>> Point._make(range(3)) # 通過一個序列或者可疊代對象建立一個對象
Point(x=0, y=1, z=2)           

複制

1.5 實踐的例子

# -*- coding: utf-8 -*-
"""
比如我們使用者擁有一個這樣的資料結構,每一個對象是擁有三個元素的tuple。
使用namedtuple方法就可以友善的通過tuple來生成可讀性更高也更好用的資料結構。
"""
from collections import namedtuple

websites = [
    ('Sohu', 'http://www.google.com/', u'張朝陽'),
    ('Sina', 'http://www.sina.com.cn/', u'王志東'),
    ('163', 'http://www.163.com/', u'丁磊')
]

Website = namedtuple('Website', ['name', 'url', 'founder'])

for website in websites:
    website = Website._make(website)
    print website


# Result:
Website(name='Sohu', url='http://www.google.com/', founder=u'\u5f20\u671d\u9633')
Website(name='Sina', url='http://www.sina.com.cn/', founder=u'\u738b\u5fd7\u4e1c')
Website(name='163', url='http://www.163.com/', founder=u'\u4e01\u78ca')           

複制

2 deque - 高效有序的list

雙端隊列,你可以從頭/尾兩端添加或删除元素。

使用list存儲資料時,按索引通路元素很快,但是插入和删除元素就很慢了,因為list是線性存儲,資料量大的時候,插入和删除效率很低。

deque是為了高效實作插入和删除操作的雙向清單,适合用于隊列和棧:

>>> from collections import deque
>>> q = deque(['a', 'b', 'c'])
>>> q.append('x')
>>> q.appendleft('y')
>>> q
deque(['y', 'a', 'b', 'c', 'x'])           

複制

deque除了實作list的append()和pop()外,還支援appendleft()和popleft(),這樣就可以非常高效地往頭部添加或删除元素。

我們也可以限制這個清單的大小,當超出你設定的限制時,資料會從對隊列另一端被擠出去(pop)。

最好的解釋是給出一個例子:

d = deque(maxlen=30)           

複制

現在當你插入30條資料時,最左邊一端的資料将從隊列中删除。

你還可以從任一端擴充這個隊列中的資料:

d = deque([1,2,3,4,5])
d.extendleft([0])
d.extend([6,7,8])
print(d)

## 輸出: deque([0, 1, 2, 3, 4, 5, 6, 7, 8])           

複制

3 defaultdict - 防dict報錯

使用dict時,如果引用的Key不存在,就會抛出KeyError。

  • 如果希望key不存在時,傳回一個預設值,就可以用defaultdict;
  • 如果希望key不存在,但是想指派成功也可以使用defaultdict。

情況一:報錯傳回預設值

>>> from collections import defaultdict
>>> dd = defaultdict(lambda: 'N/A')
>>> dd['key1'] = 'abc'
>>> dd['key1'] # key1存在
'abc'
>>> dd['key2'] # key2不存在,傳回預設值
'N/A'           

複制

注意預設值是調用函數傳回的,而函數在建立defaultdict對象時傳入。

除了在Key不存在時傳回預設值,defaultdict的其他行為跟dict是完全一樣的。

情況二:未定義key,一鍵定義

新添加内容:

from collections import defaultdict

colours = (
    ('Yasoob', 'Yellow'),
    ('Ali', 'Blue'),
    ('Arham', 'Green'),
    ('Ali', 'Black'),
    ('Yasoob', 'Red'),
    ('Ahmed', 'Silver'),
)

favourite_colours = defaultdict(list)

for name, colour in colours:
    favourite_colours[name].append(colour)

print(favourite_colours)           

複制

當你在一個字典中對一個鍵進行嵌套指派時,如果這個鍵不存在,會觸發keyError異常。 defaultdict允許我們用一個聰明的方式繞過這個問題。 首先我分享一個使用dict觸發KeyError的例子,然後提供一個使用defaultdict的解決方案。

如果是dict,會報錯:

some_dict = {}
some_dict['colours']['favourite'] = "yellow"

## 異常輸出:KeyError: 'colours'           

複制

如果是defaultdict,會如常運作:

import collections
tree = lambda: collections.defaultdict(tree)
some_dict = tree()
some_dict['colours']['favourite'] = "yellow"

## 運作正常           

複制

4 OrderedDict - 有序的dict

使用dict時,Key是無序的。在對dict做疊代時,我們無法确定Key的順序。

如果要保持Key的順序,可以用OrderedDict:

>>> from collections import OrderedDict
>>> d = dict([('a', 1), ('b', 2), ('c', 3)])
>>> d # dict的Key是無序的
{'a': 1, 'c': 3, 'b': 2}
>>> od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
>>> od # OrderedDict的Key是有序的
OrderedDict([('a', 1), ('b', 2), ('c', 3)])           

複制

再來一個案例:

>>> p = collections.OrderedDict()
>>> p["a"]=1
>>> p["b"]=2
>>> p["c"]=3
>>> print(p)
OrderedDict([('a', 1), ('b', 2), ('c', 3)])           

複制

循環建立:

>>> # 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)])           

複制

OrderedDict提供了下面的一些api。

>>> p.
p.clear(        p.fromkeys(     p.items(        p.move_to_end(  p.popitem(      p.update(
p.copy(         p.get(          p.keys(         p.pop(          p.setdefault(   p.values(           

複制

注意,OrderedDict的Key會按照插入的順序排列,不是Key本身排序:

>>> od = OrderedDict()
>>> od['z'] = 1
>>> od['y'] = 2
>>> od['x'] = 3
>>> od.keys() # 按照插入的Key的順序傳回
['z', 'y', 'x']           

複制

單地試一下update,pop,move_to_end和clear

>>> keys=["apple", "banana", "cat"] 
>>> value=[4, 5, 6] 

# update 
>>> p.update(zip(keys,value)) 
>>> p 
OrderedDict([('a', 1), ('b', 2), ('c', 3), ('apple', 4), ('banana', 5), ('cat', 6)])

# pop 
>>> p.pop('a') 
1 
>>> p 
OrderedDict([('b', 2), ('c', 3), ('apple', 4), ('banana', 5), ('cat', 6)]) 

# popitem(last=True)
>>> d = OrderedDict({'banana': 3, 'apple': 4, 'pear': 1, 'orange': 2})
>>> d
OrderedDict([('banana', 3), ('apple', 4), ('pear', 1), ('orange', 2)])
>>> d.popitem()
('orange', 2)
>>> d
OrderedDict([('banana', 3), ('apple', 4), ('pear', 1)])
>>> d.popitem(last=False)
('banana', 3)
>>> d
OrderedDict([('apple', 4), ('pear', 1)])

# move_to_end 
>>> p.move_to_end('b') 
>>> p 
OrderedDict([('c', 3), ('apple', 4), ('banana', 5), ('cat', 6), ('b', 2)]) 

# del 
>>> del(p['c'])
>>> p 
OrderedDict([('apple', 4), ('banana', 5), ('cat', 6), ('b', 2)]) 

# clear 
>>> p.clear() 
>>> p 
OrderedDict()           

複制

5 ChainMap - dict合并

ChainMap 用來成合并多個字典,但和 update 不同,它不會改變原對象,而且效率更高。

ChainMap用來将多個dict(字典)組成一個list(隻是比喻).

>>> from collections import ChainMap
>>> a = {'a': 'A', 'c': 'C'}
>>> b = {'b': 'B', 'c': 'D'}
>>> m = ChainMap(a, b)
# 構造一個ChainMap對象
>>> m
ChainMap({'a': 'A', 'c': 'C'}, {'b': 'B', 'c': 'D'})
>>> m['a']
'A'
>>> m['c'] # 擷取的是第一個字典中的值
'C'
# 将m變成一個list
>>> m.maps
[{'a': 'A', 'c': 'C'}, {'b': 'B', 'c': 'D'}]           

複制

不過,如果合并的dict之中,有同一個key,那麼會優先以第一個出現的為主。

同時,如何獲得一個dict的

keys

>>> chain.keys()
KeysView(ChainMap({'a': 1, 'b': 2}, {'b': 3, 'c': 4}))
>>> list(chain.keys())
['a', 'b', 'c']
>>> print(chainMap.items())
ItemsView(ChainMap({'user': 'guest', 'color': 'red'}, {'age': '18', 'name': 'drfish'}))           

複制

chainmap的更新:

# 更新a中的值也會對ChainMap對象造成影響
>>> a['c'] = 'E'
>>> m['c']
'E'
# 從m複制一個ChainMap對象,更新這個複制的對象并不會對m造成影響
>>> m2 = m.new_child()
>>> m2['c'] = 'f'
>>> m['c']
'E'
>>> a['c']
'E'
# parents屬性
>>> m2.parents
ChainMap({'a': 'A', 'c': 'C'}, {'b': 'B', 'c': 'D'})
# 添加新字典
>>> dict3 = { 'h' : 5 }
>>> new_chain = chain.new_child(dict3)             

複制

6 Counter - 計數

參考:Python标準庫——collections子產品的Counter類

建立的幾種方式:

>>> c = Counter()  # 建立一個空的Counter類
>>> c = Counter('gallahad')  # 從一個可iterable對象(list、tuple、dict、字元串等)建立
>>> c = Counter({'a': 4, 'b': 2})  # 從一個字典對象建立
>>> c = Counter(a=4, b=2)  # 從一組鍵值對建立           

複制

使用的方式

Counter是一個簡單的計數器,例如,統計字元出現的個數:

>>> from collections import Counter
>>> c = Counter()
>>> for ch in 'programming':
...     c[ch] = c[ch] + 1
...
>>> c
Counter({'g': 2, 'm': 2, 'r': 2, 'a': 1, 'i': 1, 'o': 1, 'n': 1, 'p': 1})
#鍵的删除
del c["g"]           

複制

Counter實際上也是dict的一個子類,上面的結果可以看出,字元’g’、‘m’、'r’各出現了兩次,其他字元各出現了一次。

使用elements()方法按照元素的出現次數傳回一個iterator(疊代器),元素以任意的順序傳回,如果元素的計數小于1,将忽略它。

>>> c = Counter(a=4, b=2, c=0, d=-2)
>>> c
Counter({'a': 4, 'b': 2, 'c': 0, 'd': -2})
>>> c.elements()
<itertools.chain object at 0x7fb0a069ccf8>
>>> next(c)
'a'
# 排序
>>> sorted(c.elements())
['a', 'a', 'a', 'a', 'b', 'b']           

複制

使用most_common(n)傳回一個list, list中包含Counter對象中出現最多前n個元素。

>>> c = Counter('abracadabra')
>>> c
Counter({'a': 5, 'b': 2, 'r': 2, 'd': 1, 'c': 1})
# 擷取出現頻率最高的3個字元
>>> c.most_common(3)  
[('a', 5), ('b', 2), ('r', 2)]           

複制

當所通路的鍵不存在時,傳回0,而不是KeyError;否則傳回它的計數。

計數器的更新(update和subtract)

>>> c = Counter('which')
>>> c.update('witch')  # 使用另一個iterable對象更新
>>> c['h']
3
>>> d = Counter('watch')
>>> c.update(d)  # 使用另一個Counter對象更新
>>> c['h']
4           

複制

鍵的删除

>>> c = Counter("abcdcba")
>>> c
Counter({'a': 2, 'c': 2, 'b': 2, 'd': 1})
>>> c["b"] = 0
>>> c
Counter({'a': 2, 'c': 2, 'd': 1, 'b': 0})
>>> del c["a"]
>>> c
Counter({'c': 2, 'b': 2, 'd': 1})           

複制

算術和集合操作

+、-、&、|操作也可以用于Counter。其中&和|操作分别傳回兩個Counter對象各元素的最小值和最大值。需要注意的是,得到的Counter對象将删除小于1的元素。

>>> c = Counter(a=3, b=1)
>>> d = Counter(a=1, b=2)
>>> c + d  # c[x] + d[x]
Counter({'a': 4, 'b': 3})
>>> c - d  # subtract(隻保留正數計數的元素)
Counter({'a': 2})
>>> c & d  # 交集:  min(c[x], d[x])
Counter({'a': 1, 'b': 1})
>>> c | d  # 并集:  max(c[x], d[x])
Counter({'a': 3, 'b': 2})           

複制

其他常見的操作:

sum(c.values())  # 所有計數的總數
c.clear()  # 重置Counter對象,注意不是删除
list(c)  # 将c中的鍵轉為清單
set(c)  # 将c中的鍵轉為set
dict(c)  # 将c中的鍵值對轉為字典
c.items()  # 轉為(elem, cnt)格式的清單
Counter(dict(list_of_pairs))  # 從(elem, cnt)格式的清單轉換為Counter類對象
c.most_common()[:-n:-1]  # 取出計數最少的n-1個元素
c += Counter()  # 移除0和負值
本文内容遵從CC3.0版權協定,轉載請注明:轉自Pythoner           

複制

參考:

廖雪峰- collections

Python标準庫之collections使用教程

Python collections使用

eastlakeside.gitbooks.io - 容器(Collections)

Python 子產品簡介 – collections

官方:python - collections