15 · Dicts: the most used Python data structure
Key→value lookups, .items() iteration, Counter, defaultdict, and dict comprehensions — everything you touch in a real ML codebase.
A dict maps arbitrary **keys** to **values** with O(1) lookup — it is the universal Python record, config, and cache.
Without this:
Without dicts, hyperparameter configs are positional tuples prone to index-off-by-one errors, label encodings require a parallel list scan, and grouping samples by category needs a full sort-then-slice pass.
A dict literal is {key: value, ...}. Keys must be hashable (strings, ints, tuples); values can be anything. Read a value with d[key] (raises KeyError if missing) or the safer d.get(key, default) (returns default instead of raising). Check existence with key in d. Since Python 3.7 dicts preserve insertion order — the order you added keys is the order you iterate.
Python (in browser)
`.get(key, default)` is almost always preferable to `d[key]` when the key might be absent — it avoids a `KeyError` without needing an explicit `if` check.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
In `{**defaults, **overrides}`, keys from `overrides` overwrite matching keys from `defaults` — right-side wins. This is the canonical pattern for config merging.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
`Counter` is a dict subclass — every Counter method works on a plain dict too, but `most_common(n)` and arithmetic between counters are exclusive bonuses.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
`defaultdict(list)` creates an empty list automatically the first time a new key is accessed — no `if key not in d: d[key] = []` boilerplate needed.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Given `a = {'x': 1, 'y': 2}` and `b = {'y': 99, 'z': 3}`, what is `{**a, **b}`?
Build frequency counters, groupby logic, and a label encoder in the Arena with server-side tests.
A dict is Python's way of expressing a *function* in the mathematical sense — a mapping from a domain of keys to a codomain of values. MML chapter 1 formalises functions and mappings; dicts are their computational embodiment.
- `d.get(key, default)` is the safe key lookup — no `KeyError`, no explicit `if` check. Use `d[key]` only when you're certain the key exists.
- `Counter` counts frequencies; `defaultdict` auto-initialises missing keys. Both are dict subclasses from `collections`.
- `{**a, **b}` merges two dicts — keys from `b` overwrite matching keys from `a`. Python 3.9+ also supports `a | b`.
Hyperparameter grids: `{'lr': 0.01, 'batch_size': 32, 'dropout': 0.3}` — every training script starts with one. Label encoding: `label_to_idx = {'cat': 0, 'dog': 1, 'bird': 2}` maps string labels to integer class indices for loss functions. `sklearn` exposes learned parameters via `model.get_params()` and `model.coef_` wrapped in a dict-like interface. PyTorch's `state_dict()` is literally a dict of parameter tensors.
If you remove it: Without dicts, a hyperparameter config is a positional tuple — swapping `lr` and `batch_size` order silently produces a bug. Label encoding without a dict requires parallel arrays and O(n) lookups at inference time.