Dictionaries¶
A dictionary is a collection of key-value pairs — like a real-world dictionary where you look up a word (key) to find its meaning (value).
Creating dictionaries¶
empty = {}
person = {"name": "Alice", "age": 25, "city": "Mumbai"}
prices = {"apple": 50, "banana": 30, "mango": 80}
print(empty, person, prices)
You can also use dict():
Accessing values¶
Use [key] or .get():
person = {"name": "Alice", "age": 25, "city": "Mumbai"}
print(person["name"]) # "Alice"
print(person.get("age")) # 25
# `[]` raises KeyError if missing
# print(person["email"]) # KeyError
# `.get()` returns None instead — safer
print(person.get("email")) # None
print(person.get("email", "no-email@example")) # default if missing
Adding & updating¶
Dicts are mutable. Assign a key to create or update:
person = {"name": "Alice", "age": 25}
# Add new key
person["city"] = "Mumbai"
# Update existing
person["age"] = 26
print(person)
# Update many at once
person.update({"job": "Engineer", "age": 27})
print(person)
Removing keys¶
person = {"name": "Alice", "age": 25, "city": "Mumbai", "job": "Engineer"}
del person["city"] # remove by key
print(person)
age = person.pop("age") # remove + return value
print(age, person)
last = person.popitem() # remove + return LAST inserted (key, value)
print(last, person)
person.clear()
print(person) # {}
Checking if a key exists¶
person = {"name": "Alice", "age": 25}
print("name" in person) # True — checks KEYS by default
print("Alice" in person) # False — that's a value
# Check values
print("Alice" in person.values()) # True
Looping over a dict¶
person = {"name": "Alice", "age": 25, "city": "Mumbai"}
# Default loop gives keys
for key in person:
print(key)
print("---")
# Get keys, values, or both
for key in person.keys():
print(key)
print("---")
for value in person.values():
print(value)
print("---")
for key, value in person.items():
print(f"{key}: {value}")
Dict comprehension¶
Same idea as list comprehension, but builds a dict:
# {key: value for ... in ...}
squares = {x: x*x for x in range(5)}
print(squares) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
# Swap keys and values
person = {"name": "Alice", "age": 25}
swapped = {v: k for k, v in person.items()}
print(swapped) # {'Alice': 'name', 25: 'age'}
# Filter
prices = {"apple": 50, "banana": 30, "mango": 80, "guava": 25}
cheap = {fruit: price for fruit, price in prices.items() if price < 50}
print(cheap)
Nested dicts¶
Common pattern for structured data:
users = {
"alice": {"age": 25, "city": "Mumbai"},
"bob": {"age": 30, "city": "Delhi"},
"carol": {"age": 22, "city": "Bangalore"},
}
# Access
print(users["alice"]["city"]) # "Mumbai"
# Add a new user
users["dave"] = {"age": 40, "city": "Chennai"}
# Loop through
for name, info in users.items():
print(f"{name} ({info['age']}) from {info['city']}")
Common patterns¶
Counting things¶
text = "the quick brown fox jumps over the lazy dog the fox"
counts = {}
for word in text.split():
counts[word] = counts.get(word, 0) + 1
print(counts)
Or use collections.Counter — built for this:
from collections import Counter
text = "the quick brown fox jumps over the lazy dog the fox"
counts = Counter(text.split())
print(counts)
print(counts.most_common(3)) # top 3 most common
Grouping items¶
from collections import defaultdict
people = [
("Alice", "Mumbai"),
("Bob", "Delhi"),
("Carol", "Mumbai"),
("Dave", "Delhi"),
("Eve", "Bangalore"),
]
by_city = defaultdict(list)
for name, city in people:
by_city[city].append(name)
print(dict(by_city))
defaultdict(list) auto-creates an empty list when you access a missing key — no if key not in dict needed.
Switching on a value (dict-as-dispatch)¶
def add(a, b): return a + b
def sub(a, b): return a - b
def mul(a, b): return a * b
ops = {"+": add, "-": sub, "*": mul}
print(ops["+"](3, 4)) # 7
print(ops["*"](3, 4)) # 12
Dictionary vs other types¶
| When to use | Pick |
|---|---|
| Look up a value by a key (name, ID, etc.) | dict |
| Just a sequence of items | list |
| Just need uniqueness | set |
| Fixed-size grouping that won't change | tuple |
Mini-project — word frequency¶
text = """
Python is great. Python is easy to learn.
Python has clear syntax. Python is popular.
"""
# Clean and split
words = text.lower().replace(".", "").split()
# Count
freq = {}
for w in words:
freq[w] = freq.get(w, 0) + 1
# Sort by frequency, descending
for word, count in sorted(freq.items(), key=lambda x: -x[1]):
print(f"{word:10} {count}")
Practice¶
What does this print?
Expected: unknown
Print 'Bob' without crashing if the key is missing
Expected: Bob
Quiz — Quick check¶
What you remember
Q1. What does person.get("missing") return if "missing" isn't a key?
- Raises
KeyError - Returns
None - Returns
0 - Returns
False
Why:
.get()returnsNonefor missing keys, unlikeperson["missing"]which raisesKeyError. You can supply a fallback:person.get("key", "default").
Q2. Which loop pattern gives you both keys AND values?
-
for x in d: -
for x in d.keys(): -
for x in d.values(): -
for k, v in d.items():
Why:
.items()yields(key, value)pairs. The defaultfor x in d:iterates over keys only.
Q3. What type can be used as a dict key?
- Only strings
- Anything immutable (str, int, float, tuple, frozenset)
- Anything
- Only strings and ints
Why: Dict keys must be hashable, which essentially means immutable. Lists and dicts can't be keys; tuples can.
Common doubts¶
Are dicts ordered in Python?
Yes, since Python 3.7 — dicts preserve insertion order as part of the language spec. Before 3.7 (and CPython 3.6 as an implementation detail), they were unordered. Today, for k in d: reliably iterates in insertion order.
When should I use defaultdict vs a regular dict?
Use defaultdict(list) (or defaultdict(int), etc.) when you're building up grouped data and want to skip the if key not in d: boilerplate. Use a regular dict when keys are known up front or when missing keys should raise.
Why does d.keys() not return a list?
It returns a view object that's tied to the dict — it updates if the dict changes, and avoids the cost of copying every key into a list. If you really need a list, do list(d.keys()). Same for .values() and .items().