Dicts & Sets
Map keys to values with dicts and store unique items with sets.
- Create and access dictionaries with [] and .get()
- Iterate over dict keys, values, and items
- Use set operations: union, intersection, difference
- Understand dict and set hashing requirements
The mapping
Mathematicians call a table that pairs each input to one output a function; Python calls it a dict. Keys point to values, exactly as a dictionary of words points to their definitions:
scores = {"Alice": 85, "Bob": 92, "Charlie": 78}
print(scores["Alice"]) # 85
print(scores.get("Dave", 0)) # 0 (default if key missing)Indexing with [] is the eager lookup: it demands the key exist. .get(key, default) is the courteous variant: if the key is missing, return the fallback instead of raising KeyError. The distinction is the difference between a claim and a question.
The dict’s toolkit
scores = {"Alice": 85, "Bob": 92}
scores.keys() # dict_keys(['Alice', 'Bob'])
scores.values() # dict_values([85, 92])
scores.items() # dict_items([('Alice', 85), ('Bob', 92)])
scores["Dave"] = 78 # add new pair
del scores["Bob"] # remove by key
scores.pop("Alice") # remove and return value
scores.update({"Eve": 95, "Frank": 88}) # merge
scores.setdefault("Grace", 0) # set only if key missingkeys, values, and items are three views of the same relation, the domain, the range, and the graph. update merges a second dict in; setdefault writes only when the key is absent, the conditional assignment that needs no if.
Walking the mapping
Iteration over a dict walks the domain by default; to see both halves, ask for items:
for name in scores: # keys
print(name)
for name, score in scores.items(): # key-value pairs
print(f"{name}: {score}")items hands you the pair directly, no manual indexing, because unpacking an entry into name, score is the natural reading of a row.
Sets: the mathematical set
A set is a set in the mathematical sense: an unordered collection with no duplicates. Repetition dissolves on entry:
colors = {"red", "blue", "green", "red"}
print(colors) # {'red', 'blue', 'green'} (duplicates removed)Uniqueness is enforced structurally, there is no second copy waiting to pollute a membership check. Membership in a set is exactly: an element is in or out, with no in-between and no earlobing.
Set operations
The algebra of sets is spelled directly. With and :
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
a | b # {1, 2, 3, 4, 5, 6} (union)
a & b # {3, 4} (intersection)
a - b # {1, 2} (difference)
a ^ b # {1, 2, 5, 6} (symmetric difference)The operators are the notation you already know. And where the theory promises speed, implementation delivers: membership testing on a set runs in against a list’s , because a set stores elements by a computed fingerprint, not by position.
The hashing requirement
Fingerprints require stability. Dict keys and set elements must be hashable, effectively immutable, so their computes stay reproducible. Strings, numbers, and tuples qualify; lists and dicts do not:
{[1, 2]: "bad"} # TypeError: unhashable type: 'list'
{(1, 2): "good"} # Works — tuple is hashableA list could not be a reliable key even if allowed: its hash would change the moment its contents do, turning the mapping into a minefield of stale lookups.
A worked example: the grade book
The relation, the domain, and the range, one table walked in three postures:
scores = {"Alice": 85, "Bob": 92, "Charlie": 78}
for name, score in scores.items():
print(f"{name}: {score}")
print(scores.get("Dave", "absent")) # absent — no KeyError
roles = {"student", "teacher", "admin"}
print("student" in roles) # True — O(1) membershipitems walks the whole graph, .get asks courteously when you do not know the key exists, and in on a set is the membership , three questions the lesson’s structures answer directly.
Common pitfalls
- Accessing missing keys.
.get()or a check withinspares you aKeyError. - Relying on dict order. Python 3.7+ preserves insertion order, but treat it as a convenience, not a contract.
- Trusting set order. A set keeps no order whatsoever; never make iteration order a dependency.
{}is an empty dict;set()is the empty set.{}is not a set. Writeset()for the empty one and{"a", "b"}for a literal, one symbol, two meanings.
🧩 Challenges
🧩 Challenge, think first, then reveal
Count the frequency of each character in "hello world" with a dict.
💡 Answer: freq = {}; for c in "hello world": freq[c] = freq.get(c, 0) + 1, the .get fallback of $0$ turns the first sighting into an increment from zero.
🧩 Challenge, think first, then reveal
Given two lists, find the elements appearing in both, using sets.
💡 Answer: set(a) & set(b) or set(a).intersection(b), the intersection is $A \cap B$, and the set machinery does the work.
🤔 Socratic Questions
- Why can’t a list serve as a dict key? What property must a key carry?
- When does a set beat a list, what do you lose, and what do you gain?
- How does
dict.get(key, default)differ fromdict[key], and when do you prefer one?
✅ Quick check
1. What does {"a": 1, "b": 2}.get("c", 0) return?
2. What is {1, 2, 3} ^ {2, 3, 4}?