Dictionaries#
A dictionary stores key-value pairs, allowing fast lookup of a value by its key:
1
2
3
4
5
6
7
8
9
10
11
12
13
| # Create a dictionary
person = {
"name": "Alice",
"age": 25,
"city": "Taipei"
}
# Empty dictionary
empty = {}
empty2 = dict()
# Create with dict()
profile = dict(name="Bob", age=30)
|
Dictionary characteristics:
- Ordered (insertion order is preserved in Python 3.7+)
- Unique keys (duplicate keys overwrite the previous value)
- Keys must be hashable (strings, numbers, and tuples are valid; lists are not)
Accessing Elements#
1
2
3
4
5
6
7
8
9
10
11
12
| person = {"name": "Alice", "age": 25, "city": "Taipei"}
# Access value by key
print(person["name"]) # Alice
print(person["age"]) # 25
# Missing key raises KeyError
# print(person["email"]) # ❌ KeyError
# Use get(): returns None or a default value when key is missing
print(person.get("email")) # None
print(person.get("email", "N/A")) # N/A
|
Modifying a Dictionary#
Add and update#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| person = {"name": "Alice", "age": 25}
# Update an existing value
person["age"] = 26
print(person) # {'name': 'Alice', 'age': 26}
# Add a new key-value pair
person["city"] = "Taipei"
print(person) # {'name': 'Alice', 'age': 26, 'city': 'Taipei'}
# update(): batch update
person.update({"age": 27, "email": "alice@example.com"})
print(person)
# {'name': 'Alice', 'age': 27, 'city': 'Taipei', 'email': 'alice@example.com'}
|
Delete#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| person = {"name": "Alice", "age": 25, "city": "Taipei"}
# pop(): remove and return value
age = person.pop("age")
print(age) # 25
print(person) # {'name': 'Alice', 'city': 'Taipei'}
# pop() accepts a default to avoid KeyError
result = person.pop("email", "not found")
print(result) # not found
# del: direct deletion
del person["city"]
print(person) # {'name': 'Alice'}
# clear(): clear the dictionary
person.clear()
print(person) # {}
|
Iterating Over a Dictionary#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| scores = {"Alice": 85, "Bob": 92, "Charlie": 78}
# Iterate over keys
for name in scores:
print(name)
# Iterate over values
for score in scores.values():
print(score)
# Iterate over key-value pairs (most common)
for name, score in scores.items():
print(f"{name}: {score} points")
# Iterate over keys (explicit form)
for name in scores.keys():
print(name)
|
Query Operations#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| person = {"name": "Alice", "age": 25, "city": "Taipei"}
# Check existence (checks keys by default)
print("name" in person) # True
print("email" in person) # False
# Check existence in values
print(25 in person.values()) # True
# Get all keys, values, and key-value pairs
print(list(person.keys())) # ['name', 'age', 'city']
print(list(person.values())) # ['Alice', 25, 'Taipei']
print(list(person.items())) # [('name', 'Alice'), ('age', 25), ('city', 'Taipei')]
# Length
print(len(person)) # 3
|
setdefault() and the Counting Pattern#
setdefault(): set a default value when key is missing#
1
2
3
4
5
6
7
8
9
10
| person = {"name": "Alice"}
# Set key if missing, and return its value
email = person.setdefault("email", "unknown@example.com")
print(email) # unknown@example.com
print(person) # {'name': 'Alice', 'email': 'unknown@example.com'}
# Does not overwrite existing keys
person.setdefault("name", "Bob")
print(person["name"]) # Alice (not overwritten)
|
Word counting pattern#
1
2
3
4
5
6
7
8
| text = "hello world hello python world hello"
word_count = {}
for word in text.split():
word_count[word] = word_count.get(word, 0) + 1
print(word_count)
# {'hello': 3, 'world': 2, 'python': 1}
|
Dictionary Comprehension#
Dict comprehension syntax is similar to list comprehension, but uses curly braces and requires both a key and a value separated by a colon ::
{key_expr: value_expr for variable in iterable}
{key_expr: value_expr for variable in iterable if condition}
Traditional approach:
1
2
3
4
| squares = {}
for x in range(1, 6):
squares[x] = x ** 2
print(squares) # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
|
Rewritten as a dict comprehension:
1
2
| squares = {x: x ** 2 for x in range(1, 6)}
print(squares) # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
|
With condition: keep only matching entries#
1
2
3
4
5
6
7
8
| # Only even-number squares
even_squares = {x: x ** 2 for x in range(1, 11) if x % 2 == 0}
print(even_squares) # {2: 4, 4: 16, 6: 36, 8: 64, 10: 100}
# Filter out failing students
scores = {"Alice": 85, "Bob": 55, "Charlie": 92, "David": 48}
passed = {name: score for name, score in scores.items() if score >= 60}
print(passed) # {'Alice': 85, 'Charlie': 92}
|
Merge two lists into a dictionary#
Use zip() to pair a names list with a values list:
1
2
3
4
5
| names = ["Alice", "Bob", "Charlie"]
scores = [85, 92, 78]
score_map = {name: score for name, score in zip(names, scores)}
print(score_map) # {'Alice': 85, 'Bob': 92, 'Charlie': 78}
|
Apply an operation to every value while keeping the keys unchanged:
1
2
3
4
5
| prices = {"apple": 30, "banana": 15, "cherry": 25}
# Apply a 20% discount to all prices
discounted = {item: price * 0.8 for item, price in prices.items()}
print(discounted) # {'apple': 24.0, 'banana': 12.0, 'cherry': 20.0}
|
Invert a dictionary (swap keys and values)#
1
2
3
| original = {"a": 1, "b": 2, "c": 3}
reversed_dict = {v: k for k, v in original.items()}
print(reversed_dict) # {1: 'a', 2: 'b', 3: 'c'}
|
⚠️ The original values must be hashable (e.g. integers, strings) to become new keys. If values are duplicated, the later key overwrites the earlier one.
Nested Dictionaries#
A dictionary’s values can themselves be dictionaries:
1
2
3
4
5
6
7
8
9
10
11
12
| students = {
"Alice": {"age": 20, "score": 85, "city": "Taipei"},
"Bob": {"age": 22, "score": 92, "city": "Kaohsiung"},
"Charlie": {"age": 21, "score": 78, "city": "Taichung"},
}
# Access nested values
print(students["Alice"]["score"]) # 85
# Iterate
for name, info in students.items():
print(f"{name} ({info['city']}): {info['score']} points")
|
Merging Dictionaries (Python 3.9+)#
1
2
3
4
5
6
7
8
9
10
11
12
| defaults = {"color": "blue", "size": "M", "quantity": 1}
custom = {"color": "red", "quantity": 5}
# Merge (custom values override defaults)
merged = defaults | custom
print(merged)
# {'color': 'red', 'size': 'M', 'quantity': 5}
# In-place update
defaults |= custom
print(defaults)
# {'color': 'red', 'size': 'M', 'quantity': 5}
|
Practical Examples#
Vote tally#
1
2
3
4
5
6
7
8
9
10
| votes = ["Alice", "Bob", "Alice", "Charlie", "Bob", "Alice", "Bob"]
tally = {}
for vote in votes:
tally[vote] = tally.get(vote, 0) + 1
winner = max(tally, key=tally.get)
print(f"Vote counts: {tally}")
print(f"Winner: {winner}")
# Vote counts: {'Alice': 3, 'Bob': 3, 'Charlie': 1}
|
Grouping data#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| students = [
{"name": "Alice", "city": "Taipei"},
{"name": "Bob", "city": "Kaohsiung"},
{"name": "Charlie", "city": "Taipei"},
{"name": "David", "city": "Kaohsiung"},
]
by_city = {}
for s in students:
city = s["city"]
by_city.setdefault(city, []).append(s["name"])
for city, names in by_city.items():
print(f"{city}: {', '.join(names)}")
# Taipei: Alice, Charlie
# Kaohsiung: Bob, David
|