Collections Best Practices
Practical rules for choosing and using Python's built-in containers without performance traps or readability debt.
Search across all documentation pages
Practical rules for choosing and using Python's built-in containers without performance traps or readability debt.
dict[str, int]) for clearer contracts.dict for keyed lookup, set for membership, list for ordered sequences. Document non-obvious choices.deque for FIFO/LIFO queues instead of list.pop(0). O(1) vs O(n) at front.heapq for priority scheduling; bisect for sorted insertions. Not sorted() on every insert.Counter and defaultdict over manual key-exists boilerplate. Fewer branches, clearer intent.copy.deepcopy when independence required. dict.copy() shares inner lists.sorted(s) for stable display only.{v: k}. Colliding values overwrite silently.get or try/except KeyError intentionally. d[k] when key must exist; get when optional.set once for repeated membership in loops. Avoid O(n) in list in hot paths.sum/any/max for large streams. Skip materializing million-item lists.array.array or bytes for compact numeric/binary buffers. Not list of ints for wire protocols.keys() snapshot unless mutating during iteration. list(d) when deleting while looping.dict[str, list[Event]], not bare dict. Self-documenting structures.NamedTuple or dataclass instead of positional tuple indexing for records. row[3] obscures meaning.| merge for immutable config overlays (3.9+). base | overrides reads left-to-right.list(dict.fromkeys(items)). Idiomatic one-liner.MappingProxyType or typed settings object.[] vs None. Callers should not guess missing vs empty.move_to_end LRU patterns. Regular dict handles insertion order otherwise.
Tuple for fixed small bundles; list when returning variable-length homogeneous collection.
__slots__ for millions of small fixed-field objects. Premature for typical app records.
Counter adds multiset operators and most_common - prefer for frequency work.
Convert dict(defaultdict) before JSON - factory not serialized.
Yes for map/filter transforms. Switch to loop for side effects or complex branching.
dataclass/Pydantic for domain objects with behavior; dict for JSON passthrough or dynamic keys.
Layered config search without copying - env over defaults. Flatten when persisting.
When a set of tags must be a dict key or cache entry - otherwise plain set.
Linear search on list inside loop - fix with set/dict index built once.
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