What are defaultdict and OrderedDict and when would you use them?
`defaultdict` and `OrderedDict` are both subclasses of `dict` in `collections`, each adding a specialized behavior on top of the standard dictionary.
**`defaultdict`** takes a *default_factory* callable as its first argument. When you access a key that doesn't exist, instead of raising `KeyError`, it calls `default_factory()` to create a default value, inserts it under that key, and returns it. This eliminates the common `dict.setdefault()` or `if key not in d` boilerplate.
Common default factories: - `defaultdict(list)` — grouping: `d[key].append(item)` works without initializing the list - `defaultdict(int)` — counting: `d[key] += 1` works without checking if key exists - `defaultdict(set)` — grouping unique values: `d[key].add(item)` - `defaultdict(lambda: defaultdict(int))` — nested counting tables
Important nuance: `default_factory` is only invoked by `__missing__`, which is called by `__getitem__`. Using `d.get(key)` does *not* trigger the factory — it returns `None` (or the specified default). This catches people who expect `.get()` to auto-create.
**`OrderedDict`** preserves insertion order and exposes `move_to_end(key, last=True)` to move a key to the beginning or end. In Python 3.7+, the built-in `dict` also preserves insertion order as a language guarantee (not just an implementation detail). This makes `OrderedDict` less necessary for most use cases.
However, `OrderedDict` still has two advantages: it provides `move_to_end()` for O(1) reordering (implemented as a doubly-linked list), and its `__eq__` considers order—two `OrderedDict`s with the same keys but different insertion order are *not* equal, whereas regular `dict`s consider only key-value pairs.
Practical use: `OrderedDict` as an LRU cache backbone — `move_to_end` on access, `popitem(last=False)` to evict the oldest. This is the pattern Python's `functools.lru_cache` internally mirrors.
Both classes inherit all standard `dict` methods, so they're drop-in replacements where appropriate.
Explains defaultdict factory mechanism and gives two concrete use cases (counting, grouping), correctly states that Python 3.7+ dict preserves order, identifies move_to_end as OrderedDict's key differentiator.
Explains that .get() doesn't trigger defaultdict factory, mentions __missing__ as the mechanism, explains OrderedDict.__eq__ considers order while dict.__eq__ doesn't, and gives the LRU cache pattern as a concrete OrderedDict use case.
Reading the answer is step one. Explaining it unprompted — under interview pressure — is what actually matters. Get AI-graded feedback on your answer with follow-up probes on your weak points.
Get Graded — Free Assessment