---
title: "Python Collections Cheatsheet"
slug: "python-collections"
category: "cheatsheets"
tags: ["cheatsheets", "python", "collections", "data-structures", "reference", "standard-library"]
status: "stable"
last_updated: 2026-05-14
summary: "Python collections module reference: Counter, defaultdict, namedtuple, deque, ChainMap, and OrderedDict with use cases and examples."
related:
  [
    "[[coding/python]]",
    "[[coding/python-typing]]",
    "[[coding/python-performance]]",
    "[[cheatsheets/python-regex]]",
    "[[cheatsheets/javascript-array-methods]]",
    "[[coding/python-async]]",
    "[[cheatsheets/index|Cheatsheets]]",
  ]
---

## Overview

The `collections` module extends Python's built-in types with specialized containers. Each type solves a specific pattern more cleanly than a plain dict or list. This card maps each collection to its primary use case and shows the API surface that matters in daily work. For type annotation patterns, see [[coding/python-typing]].

```python
from collections import Counter, defaultdict, namedtuple, deque, ChainMap, OrderedDict
```

## Counter

Count hashable objects. Built-in `most_common`, arithmetic, and set operations.

| Pattern | Code | Notes |
| --- | --- | --- |
| Count from iterable | `Counter("aababc")` | `{'a': 3, 'b': 2, 'c': 1}` |
| Count from dict | `Counter({'a': 3, 'b': 2})` | Accepts any mapping. |
| Most common N | `c.most_common(3)` | Returns list of (element, count) tuples, descending. |
| Add counts | `c + Counter("ab")` | Returns new Counter; negative counts dropped. |
| Subtract counts | `c.subtract("aab")` | In-place; keeps zero and negative counts (unlike `-`). |
| Elements | `list(c.elements())` | Expand back to iterable; repeats each element count times. |
| Missing key | `c["missing"]` | Returns `0`, not `KeyError`. |

```python
words = "the quick brown fox jumps over the lazy dog the fox".split()
freq = Counter(words)
print(freq.most_common(3))  # [('the', 3), ('fox', 2), ...]
```

Use `Counter` for word frequency, histogram bins, and vote tallies.

## defaultdict

Dict that calls a factory for missing keys instead of raising `KeyError`.

| Pattern | Code | Notes |
| --- | --- | --- |
| List of values per key | `defaultdict(list)` | `d[key].append(v)` without checking membership. |
| Count with int | `defaultdict(int)` | `d[key] += 1` without initialization. |
| Nested dict | `defaultdict(dict)` | `d[outer][inner] = v` in one step. |
| Custom factory | `defaultdict(lambda: "N/A")` | Any zero-arg callable. |
| Access without inserting | `d.get(key)` | `d[key]` inserts the default; `.get()` does not. |

```python
# Group words by first letter
from collections import defaultdict
groups = defaultdict(list)
for word in ["apple", "avocado", "banana", "blueberry", "cherry"]:
    groups[word[0]].append(word)
# {'a': ['apple', 'avocado'], 'b': ['banana', 'blueberry'], 'c': ['cherry']}
```

Prefer `defaultdict(list)` over `setdefault` in loops; it reads more clearly.

## namedtuple and dataclass

`namedtuple` creates lightweight immutable record types. Use `dataclass` when you need mutability or methods.

| API | Code | Notes |
| --- | --- | --- |
| Define | `Point = namedtuple("Point", ["x", "y"])` | Also accepts space-separated string `"x y"`. |
| Instantiate | `p = Point(1, 2)` | Positional or keyword arguments. |
| Access | `p.x`, `p[0]` | Both attribute and index access work. |
| As dict | `p._asdict()` | Returns `dict`; useful for serialization. |
| Replace a field | `p._replace(x=10)` | Returns new instance; original unchanged. |
| Defaults | `Point = namedtuple("Point", ["x", "y"], defaults=[0, 0])` | Python 3.6.1+. |
| Typed variant | `from typing import NamedTuple` | Allows per-field type hints. |

```python
from typing import NamedTuple

class Config(NamedTuple):
    host: str
    port: int = 5432
    ssl: bool = True

cfg = Config(host="localhost")
```

## deque

Double-ended queue; O(1) append and pop from both ends. Use instead of a list when you need a sliding window or FIFO queue.

| Operation | Code | Notes |
| --- | --- | --- |
| Create bounded | `deque(maxlen=100)` | Old items auto-dropped when full. |
| Append right | `d.append(v)` | Same as list. |
| Append left | `d.appendleft(v)` | O(1); list insert(0, v) is O(n). |
| Pop right | `d.pop()` | Raises `IndexError` if empty. |
| Pop left | `d.popleft()` | O(1) FIFO dequeue. |
| Rotate | `d.rotate(n)` | Right-rotate by n; negative rotates left. |
| Extend both ends | `d.extend(iterable)`, `d.extendleft(iterable)` | `extendleft` reverses insertion order. |

```python
# Sliding window of last 5 log lines
log_tail = deque(maxlen=5)
for line in read_log():
    log_tail.append(line)
```

## ChainMap

Treats multiple dicts as a single logical view. Lookups search dicts left to right; writes go to the first dict.

| Pattern | Code | Notes |
| --- | --- | --- |
| Create | `ChainMap(user_cfg, project_cfg, defaults)` | First dict has highest priority. |
| Add a layer | `cm.new_child({"key": "val"})` | Returns new ChainMap; original unchanged. |
| Remove top layer | `cm.parents` | View without the first map. |
| Write through | `cm["key"] = v` | Writes to the first dict only. |
| All maps | `cm.maps` | List of underlying dicts in priority order. |

```python
import os
from collections import ChainMap

# Config priority: CLI args > env vars > defaults
defaults = {"debug": False, "port": 8000, "host": "0.0.0.0"}
env = {k.lower(): v for k, v in os.environ.items() if k in ("PORT", "HOST", "DEBUG")}
cli = {"port": 9000}  # from argparse

config = ChainMap(cli, env, defaults)
print(config["port"])  # 9000 (cli wins)
```

## Common gotchas

- `Counter` subtraction with `-` drops zero and negative counts silently. Use `.subtract()` when you need to keep those counts for further arithmetic.
- `defaultdict` inserts the default value on key access (`d[missing]`). Iterating `d.keys()` after accidental reads produces unexpected entries. Use `d.get(key)` when you only want to check membership.
- `namedtuple` fields are positional. Renaming a field in the definition breaks any code that uses positional construction. Prefer `NamedTuple` with keyword defaults for public APIs.
- `deque` with `maxlen` does not raise on overflow; it silently drops the oldest item. If dropping data silently is wrong for your use case, check `len(d) == d.maxlen` before appending.
- `ChainMap` writes go to the first dict. If the first dict is empty and you read then write the same key, the value is written to the empty dict and the original lower-priority dict is unchanged.
- `OrderedDict` is rarely needed in Python 3.7+ because plain `dict` preserves insertion order. Use `OrderedDict` only when you need `move_to_end` or equality that respects order.

## Related

- [[coding/python]]
- [[coding/python-typing]]
- [[coding/python-performance]]
- [[cheatsheets/python-regex]]
- [[cheatsheets/javascript-array-methods]]
- [[coding/python-async]]
- [[cheatsheets/index|Cheatsheets]]
