Dicts & sets
Hash tables in disguise: fast lookup by key, insertion order, set algebra, and what 'hashable' really means.
Dictionaries
A dict maps keys → values. Keys must be hashable (immutable things like str, int, tuple).
user = {"name": "Ada", "langs": ["python"]}
user["age"] = 36 # add / update
print(user["name"], user.get("email"), user.get("email", "n/a"))
print("age" in user, len(user))
del user["age"]
print(user.pop("langs"), user)| Method | Does |
|---|---|
d.get(k, default) | value or default, never raises |
d.setdefault(k, v) | get, inserting v if missing |
d.update(other) / d | other | merge |
d.keys() d.values() d.items() | live views |
d.pop(k) d.popitem() | remove |
stock = {"apple": 3, "kiwi": 0}
for fruit, qty in stock.items():
print(f"{fruit}: {qty}")
stock |= {"kiwi": 5, "mango": 2}
print(stock, list(stock)) # insertion order is keptprint(hash("name"), hash(42), hash((1, 2)))
print(hash(42) == 42) # small ints hash to themselvestry:
{[1, 2]: "nope"}
except TypeError as e:
print("TypeError:", e)
print({(1, 2): "fine"})⚠️ Gotcha: string hashes are randomized per process (to prevent attacks), so hash("abc") differs between runs. Never store hashes or rely on set iteration order for strings.
Handy dict tools
from collections import Counter, defaultdict
words = "the cat and the hat and the bat".split()
print(Counter(words).most_common(2))
by_len = defaultdict(list)
for w in words:
by_len[len(w)].append(w)
print(dict(by_len))
print({w: len(w) for w in set(words)}) # dict comprehension
print(dict(zip(["a", "b"], [1, 2])))Sets
A set is an unordered collection of unique, hashable items: a dict with keys only.
seen = {"a", "b"}
seen.add("c"); seen.discard("z")
print(len({1, 1, 2, 3}), "a" in seen)
a, b = {1, 2, 3, 4}, {3, 4, 5}
print(a | b, a & b, a - b, a ^ b) # union, intersection, difference, symmetric
print({1, 2} <= a, a.isdisjoint({9}))
print(frozenset({1, 2})) # immutable & hashable set⚠️ Gotcha: {} is an empty dict. An empty set is set().
import sys nums = list(range(100_000)) print(sys.getsizeof(nums), sys.getsizeof(set(nums)), sys.getsizeof(dict.fromkeys(nums)))
🧭 Scenario: Deduplicating a mailing list while keeping the original order: a set loses order, but dict.fromkeys keeps the first occurrence of each key in insertion order.
emails = ["b@x.com", "a@x.com", "b@x.com", "c@x.com", "a@x.com"] print(list(dict.fromkeys(emails)))
🧭 Scenario: Finding which users are in both the "newsletter" and "paid" groups is one line of set algebra: newsletter & paid. Users who churned: last_month - this_month.