Dictionaries
Key-value mapping, methods, and internals
Why it matters
Hash maps solve a huge class of problems in O(1) average time.
The idea
A dict is a fast lookup table: key → value. Keys must be hashable (so: strings, numbers, tuples — not lists). Since Python 3.7, dicts remember insertion order.
Try it
Build, lookup, default values:
prices = {"apple": 1.0, "banana": 0.5}
prices["cherry"] = 2.5
print(prices)
# .get() returns a default instead of raising KeyError
print(prices.get("grape", 0.0))
# setdefault() inserts if missing, then returns the value
prices.setdefault("date", 3.0)
print(prices)
Counting — the classic "frequency" idiom:
from collections import Counter
text = "mississippi"
counts = Counter(text)
print(counts)
print(counts.most_common(2))
Iterating: items() yields (key, value) tuples — perfect for unpacking.
scores = {"Ada": 95, "Linus": 88, "Margaret": 99}
for name, score in scores.items():
print(f"{name:>10}: {score}")
# Dict comprehension
inverted = { score: name for name, score in scores.items() }
print(inverted)
Core dict methods (must know)
| Method | What it does | Example |
| --- | --- | --- |
| get(k, d) | safe lookup | d.get("x", 0) |
| keys() | view of keys | list(d.keys()) |
| values() | view of values | list(d.values()) |
| items() | view of pairs | list(d.items()) |
| update(...) | merge/update | d.update({"x":1}) |
| pop(k) | remove key | d.pop("x") |
| popitem() | remove last pair | d.popitem() |
| setdefault(k, d) | get or set | d.setdefault("x", 0) |
| copy() | shallow copy | d.copy() |
| fromkeys(keys, v) | init | dict.fromkeys(keys, 0) |
Grouping pattern
setdefault makes "bucket items by a key" a one-liner:
groups = {}
for item in items:
groups.setdefault(item[0], []).append(item)
Two Sum pattern
The canonical "remember what you've seen" hash trick — O(n) instead of O(n²):
def two_sum(nums, target):
seen = {}
for i, x in enumerate(nums):
need = target - x
if need in seen:
return [seen[need], i]
seen[x] = i
Quick check
- Q: What does
dict.get(k)return if the key is missing? A:None(or the default you provide).
Mini drills
- Count characters in a string.
- Find the first repeated number.
- Build a word → count dictionary.
Do's and don'ts
- Do use
in dto test keys. - Do prefer
getfor optional access. - Don't mutate a dict while iterating over it.
- Don't use unhashable keys (
list,dict,set).
Going deeper — how dictionaries work
Hash table internals
- Hash table: keys are hashed to an index in a table.
- Collisions: different keys can map to the same index.
- Resolution: CPython uses open addressing with probing (fast on average).
- Load factor: as the table fills, Python resizes it to keep lookups fast.
Hashability rules
- Hashable:
int,float,str,tuple(if its elements are hashable),frozenset. - Unhashable:
list,dict,set.
Order guarantee
- Python 3.7+ preserves insertion order (an official language guarantee).
Common mistakes
- Mistake: Accessing missing keys with
[]. Fix: Useget(). - Mistake: Overwriting values unintentionally. Fix: Inspect keys before assignment.
- Mistake: Using a list as a key. Fix: Use a tuple or
frozenset. - Mistake: Assuming
dict.keys()is a list. Fix: Wrap withlist(...)when needed.
Key takeaways
- Keys must be hashable; values can be anything.
dict.get(k, default)avoidsKeyError;setdefaultinserts-if-missing.collections.Counteris the goto for frequency counts.- Dict comprehensions:
{k: v for ... if ...}mirror list comprehensions. get,set,in,popare ~O(1) average; worst case O(n) under heavy collisions.