Dictionaries
A dictionary maps keys to values: {"alice": 90, "bob": 70}. Think of it as a labelled lookup — you fetch a value by its key, not by position. It's how Python holds structured data in memory, and it mirrors a JSON object exactly.
Look up with d[key]. If the key is missing, d[key] raises KeyError. d.get(key) is the safe alternative: it returns None (or a default you supply, d.get(key, 0)) instead of crashing.
Add or update with d[key] = value — same syntax for both: a new key is inserted, an existing key is overwritten. key in d tests whether a key is present (not a value).
To loop, three views:
d.keys()— the keys.d.values()— the values.d.items()—(key, value)pairs, perfect to unpack:for name, score in d.items():.
As of Python 3.7+, dicts keep insertion order — iterating gives keys back in the order you added them.
Syntax
profiles = {"alice": 90, "bob": 70}
profiles["alice"] # 90
profiles.get("nobody") # None (no crash)
profiles.get("nobody", 0) # 0 (custom default)
profiles["carol"] = 88 # add
profiles["alice"] = 95 # update
"bob" in profiles # True (checks KEYS)
for name, score in profiles.items():
...Worked examples
.get() avoids KeyError; supply a default
profiles = {"alice": 90, "bob": 70}
print(profiles["alice"]) # 90
print(profiles.get("charlie")) # None
print(profiles.get("charlie", 0)) # 0
# profiles["charlie"] → KeyError!Add, update, and loop over .items()
profiles = {"alice": 90, "bob": 70}
profiles["carol"] = 88 # add a new key
profiles["alice"] = 95 # update an existing key
for name, score in profiles.items():
print(f"{name}: {score}")
# Output:
# alice: 95
# bob: 70
# carol: 88in checks keys; find the top scorer
def top_scorer(profiles):
best_user = None
best_score = -1
for name, score in profiles.items():
if score > best_score:
best_score = score
best_user = name
return best_user
p = {"alice": 90, "bob": 70, "charlie": 95}
print("bob" in p) # True (checks keys)
print(top_scorer(p)) # charlieCommon mistakes & gotchas
d[missing] raises KeyError
Indexing a key that isn't there crashes with KeyError. When a key might be absent, use d.get(key) (returns None) or d.get(key, default). Check first with if key in d: when you need to branch.
in checks keys, not values
"bob" in profiles tests the *keys*. To check values, use 90 in profiles.values(). Forgetting this leads to membership tests that quietly always fail.
Keys must be hashable; duplicates collapse
Keys have to be immutable (str, int, tuple — not list or dict). And a dict can't hold two of the same key: {"a": 1, "a": 2} keeps only {"a": 2} — the last assignment wins.
Why it matters
Dictionaries are everywhere data has structure: API responses, config, JSON, counting and grouping, in-memory caches and lookups. The `.get()`-with-default habit alone prevents a whole category of `KeyError` crashes, and `.items()` is how you iterate structured records cleanly.