collections Module
The collections module extends built-in containers with specialized types tuned for common patterns - grouping, counting, double-ended queues, and layered configuration.
Search across all documentation pages
The collections module extends built-in containers with specialized types tuned for common patterns - grouping, counting, double-ended queues, and layered configuration.
from collections import Counter, defaultdict, deque
words = Counter("abracadabra".split())
by_len: defaultdict[int, list[str]] = defaultdict(list)
queue: deque[str] = deque(maxlen=100)When to reach for this:
if key not in dictChainMapfrom collections import ChainMap, Counter, defaultdict, deque
def group_by(items: list[dict], field: str) -> dict[str, list[dict]]:
groups: defaultdict[str, list[dict]] = defaultdict(list)
for item in items:
groups[str(item[field])].append(item)
return dict(groups)
def top_n_words(text: str, n: int) -> list[tuple[str, int]]:
counts = Counter(word.lower() for word in text.split())
return counts.most_common(n)
def sliding_window(values: list[int], size: int) -> list[int]:
window: deque[int] = deque(maxlen=size)
sums: list[int] = []
for v in values:
window.append(v)
if len(window) == size:
sums.append(sum(window))
return sums
def merged_config(*maps: dict[str, object]) -> ChainMap:
return ChainMap(*maps)
if __name__ == "__main__":
rows = [{"role": "dev", "name": "a"}, {"role": "dev", "name": "b"}]
print(group_by(rows, "role"))
print(top_n_words("a b a c a b", 2))
print(sliding_window([1, 2, 3, 4, 5], 3))What this demonstrates:
defaultdict(list) appends without existence checksCounter.most_common returns ranked pairsdeque(maxlen=...) auto-evicts oldest for rolling windowsChainMap searches dict stack for first matching key__missing__.+, -, &, |.move_to_end.| Type | Use |
|---|---|
deque | Queue, stack, rolling window |
Counter | Word counts, histograms |
defaultdict | Group-by, adjacency lists |
ChainMap | Scoped settings layers |
# Counter as multiset
c1 = Counter(a=3, b=1)
c2 = Counter(a=1, c=2)
print(c1 + c2)
# move_to_end on OrderedDict for LRU-ish orderinglist, int, set.subtract knowingly or filter positives.move_to_end LRU patterns.| Alternative | Use When | Don't Use When |
|---|---|---|
plain dict | Simple maps | Repetitive missing-key boilerplate |
pandas.value_counts | DataFrame columns | Stdlib-only script |
heapq | Priority ordering | FIFO queue only |
functools.lru_cache | Function memoization | Counting arbitrary iterables |
Mostly - regular dict preserves insert order. Keep OrderedDict for move_to_end LRU behaviors.
defaultdict cleaner for accumulation. setdefault fine for occasional missing keys.
Yes if hashable. Often count strings or tuples extracted from records.
Append/pop thread-safe in CPython due to GIL; still coordinate compound operations across threads.
ChainMap(os.environ, defaults) - env overrides defaults without copying.
Uses heap for top-n - efficient when n << unique keys.
Moved toward typing.NamedTuple and dataclasses - still available as collections.namedtuple.
Expands counts to repeated items - useful for re-feeding multiset into algorithms.
Never list.pop(0) in hot loops - O(n). Always deque.popleft().
Convert to plain dict first: dict(dd) - factory not preserved in JSON naturally.
Stack versions: This page was written for Python 3.14.0 (stable 3.14, maintenance 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, and uv 0.6+.
Reviewed by Chris St. John·Last updated Jul 16, 2026