collections — specialised container datatypes#

Part of a series demonstrating the 5 most-imported modules across the top PyPI packages (from imports_ranked.csv). Rank 4 of 5 — imported by 62.0% of crawled packages.

High-value containers beyond list/dict/set: Counter, defaultdict, deque, namedtuple, OrderedDict, and ChainMap.

Counter — tallying and ranking#

Exactly the tool our analysis script leaned on to count imports.

from collections import Counter

words = 'the cat sat on the mat the cat ran'.split()
c = Counter(words)
print(c)
print('most_common(2):', c.most_common(2))
c.update(['cat', 'dog'])
print("after update    :", c['cat'], 'cats,', c['dog'], 'dog')
Counter({'the': 3, 'cat': 2, 'sat': 1, 'on': 1, 'mat': 1, 'ran': 1})
most_common(2): [('the', 3), ('cat', 2)]
after update    : 3 cats, 1 dog

defaultdict — no more KeyError#

Missing keys are auto-created via a factory (list, int, set, …).

from collections import defaultdict

groups = defaultdict(list)
for name in ['ann', 'bob', 'amy', 'ben']:
    groups[name[0]].append(name)
print(dict(groups))

counts = defaultdict(int)
for ch in 'banana':
    counts[ch] += 1
print(dict(counts))
{'a': ['ann', 'amy'], 'b': ['bob', 'ben']}
{'b': 1, 'a': 3, 'n': 2}

namedtuple — lightweight, immutable records#

from collections import namedtuple

Point = namedtuple('Point', ['x', 'y'])
p = Point(3, 4)
print(p, '| x =', p.x, '| as dict:', p._asdict())
print('replace:', p._replace(y=99))
Point(x=3, y=4) | x = 3 | as dict: {'x': 3, 'y': 4}
replace: Point(x=3, y=99)

deque — fast appends/pops at both ends#

O(1) at either end (unlike a list’s O(n) insert(0, ...)). Supports a maxlen for sliding windows.

from collections import deque

d = deque([2, 3, 4])
d.appendleft(1)
d.append(5)
print(d)
print('popleft:', d.popleft(), '-> ', d)

window = deque(maxlen=3)
for i in range(6):
    window.append(i)
print('rolling window of last 3:', list(window))
deque([1, 2, 3, 4, 5])
popleft: 1 ->  deque([2, 3, 4, 5])
rolling window of last 3: [3, 4, 5]

OrderedDict and ChainMap#

from collections import OrderedDict, ChainMap

od = OrderedDict([('a', 1), ('b', 2)])
od.move_to_end('a')
print('OrderedDict:', od)

defaults = {'color': 'black', 'size': 'M'}
user = {'size': 'L'}
settings = ChainMap(user, defaults)   # user overrides defaults
print('ChainMap:', settings['size'], settings['color'])
OrderedDict: OrderedDict([('b', 2), ('a', 1)])
ChainMap: L black