Warming up the neural circuits...
By the end of this chapter you will:
Lookup by name beats search by position, every time. If you have a list of users and want to find Alice's age, you'd loop through the whole list. With a dict, you write users["Alice"]["age"] — instant lookup.
Dictionaries are Python's hash map — the most important data structure for modeling real-world data. Sets are hash-based collections for unique items and fast membership testing. Master both, and you can model any relationship.
# Creating dicts
empty = {}
user = {"name": "Alice", "age": 30, "active": True}
from_list = dict([("a", 1), ("b", 2)])
# Accessing
print(user["name"]) # 'Alice'
# user["email"] # KeyError!
print(user.get("email")) # None (safe)
print(user.get("email", "N/A")) # 'N/A' (default)| Operation | Code | Result |
|---|---|---|
| Create empty | {} | Empty dict |
| Create with values | {"a": 1} | Dict with one entry |
| Access | d["key"] | Value or KeyError |
| Safe access | d.get("key") | Value or None |
| With default | d.get("key", default) | Value or default |
user = {"name": "Alice", "age": 30}
# Adding/Updating
user["email"] = "alice@example.com" # add
user["age"] = 31 #
user = {"name": "Alice", "age": 30, "active": True}
# Keys
for key in user.keys():
print(key)
# Values
defaults = {"color": "blue", "size": "medium"}
overrides = {"color": "red", "price": 29.99}
# | operator (Python 3.9+) — returns new dict
merged = defaults |
# Creating sets
unique = {1, 2, 3, 3, 4} # {1, 2, 3, 4}
from_list = set([1, 2, 2, 3]) # {1, 2, 3}
# Membership (O(1))
print
Think of dicts as phone books:
| Mistake | Why it's wrong | Fix |
|---|---|---|
d["key"] when key might not exist | KeyError | d.get("key") or d.get("key", default) |
d = {} then d["key"] | Works (empty dict) | Fine, but set() is for empty sets |
set = {1, 2, 3} then set.add(4) | set shadows built-in | Use my_set = {1, 2, 3} |
| Iterating and modifying dict size | RuntimeError: dictionary changed size during iteration | Collect changes, apply after loop |
| Using mutable values as dict keys | TypeError: unhashable type: 'list' | Use tuples instead of lists as keys |
Start with {"name": "Alice", "age": 30, "email": "alice@example.com"}{"name": "Alice", "age": 30, "phone": "555-1234"}get() to safely access a missing key without raising KeyError.user = {"name": "Alice"}defaults = {"color": "blue"}, overrides = {"color": "red", "size": "large"}{"color": "red", "size": "large"}active = {"Alice", "Bob", "Charlie"}, premium = {"Bob", "Charlie", "Dave"}{"Bob", "Charlie"}Beginner:
"What's the difference between d["key"] and d.get("key")?"
d["key"]raises KeyError if the key doesn't exist.d.get("key")returns None (or a default value you specify). Useget()when the key might be missing.
"How do you remove duplicates from a list?"
Convert to a set:
list(set(my_list)). Sets automatically remove duplicates. Note: this doesn't preserve order. For order preservation, uselist(dict.fromkeys(my_list)).
Senior:
"What's the time complexity of dict lookup vs list lookup?"
Dict lookup is O(1) average — it uses a . List lookup with
inis O(n) — it scans every . This is why dicts are preferred for large datasets when you need fast lookups by key.
{} to create, d[key] to access, d.get(key) for safe access.setdefault() to get-or-create. Use | to merge (Python 3.9+).{1, 2, 3} to create. in is O(1).| union, & intersection, - difference, ^ symmetric difference.I have a dict. I want to…
├── Access safely → d.get("key") or d.get("key", default)
├── Add/update → d["key"] = value
├── Remove → pop(key) or del d[key]
├── Merge → d1 | d2 (3.9+)
├── Iterate → for k, v in d.items():
└── Check exists → "key" in d
I have a set. I want to…
├── Dedup → set(list)
├── Intersection → a & b
├── Union → a | b
├── Difference → a - b
└── Check membership → x in sWhat does d.get('key') return if the key doesn't exist?
| Method | Returns | Mutates | Use when |
|---|---|---|---|
d[key] = val | — | ✅ Yes | Add/update entry |
pop(key) | The value | ✅ Yes | Remove and return |
del d[key] | None | ✅ Yes | Remove (no return) |
setdefault(key, default) | Value | ✅ Yes | Get or create |
| Method | Returns | Use when |
|---|---|---|
keys() | View of keys | Need all keys |
values() | View of values | Need all values |
items() | View of (key, value) | Need pairs |
for key in d: | Keys | Direct iteration |
| Method | Mutates | Use when |
|---|---|---|
d1 | d2 | ❌ No | Merge into new dict |
d1.update(d2) | ✅ Yes | Update in place |
{**d1, **d2} | ❌ No | Merge (pre-3.9) |
| Operation | Code | Result |
|---|---|---|
| Union | a | b | All items from both |
| Intersection | a & b | Items in both |
| Difference | a - b | Items in a, not in b |
| Symmetric diff | a ^ b | Items in either, not both |
No. Lists are mutable and unhashable. Dict keys must be hashable (immutable). Use tuples instead:
{(1, 2): "value"}works,{[1, 2]: "value"}raises TypeError.