Skip to content

📖 Dictionaries and Maps

Dictionaries are Python's key-value data structure — perfect for looking up values by a unique identifier.


What is a Dictionary?

Think of a dictionary like a phone book: you look up a name (key) to find a phone number (value).

phonebook = {
    "Alice": "555-1234",
    "Bob": "555-5678",
    "Charlie": "555-9999"
}
# Key: "Alice" -> Value: "555-1234"

Creating Dictionaries

# Empty dictionary
empty = {}
empty = dict()

# With initial values
person = {"name": "Alice", "age": 25, "city": "NYC"}

# From list of tuples
items = dict([("a", 1), ("b", 2), ("c", 3)])

# From keyword arguments
config = dict(debug=True, version="1.0", max_size=100)

# Dictionary comprehension
squares = {x: x**2 for x in range(5)}
# {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

Accessing Values

person = {"name": "Alice", "age": 25, "city": "NYC"}

# Bracket notation
print(person["name"])  # "Alice"
print(person["age"])   # 25

# Get method (safer - returns None if missing)
print(person.get("name"))      # "Alice"
print(person.get("country"))   # None
print(person.get("country", "Unknown"))  # "Unknown" (default)

# Bracket notation raises KeyError if missing!
print(person["country"])  # ❌ KeyError: 'country'

Modifying Dictionaries

Adding/Updating Values

person = {"name": "Alice"}

person["age"] = 25           # Add new key
person["name"] = "Alicia"    # Update existing key
person.update({"city": "NYC", "age": 26})  # Update multiple

print(person)  # {"name": "Alicia", "age": 26, "city": "NYC"}

Removing Values

person = {"name": "Alice", "age": 25, "city": "NYC"}

age = person.pop("age")      # Remove and return value
print(age)  # 25

del person["city"]           # Just delete (no return)

person.clear()               # Remove all items

Common Dictionary Methods

Method Description Example
get(key, default) Get value or default d.get('x', 0)
keys() All keys list(d.keys())
values() All values list(d.values())
items() Key-value pairs list(d.items())
pop(key) Remove and return d.pop('x')
update(dict2) Merge/update d.update({'a': 1})
setdefault(key, default) Get or set default d.setdefault('x', [])
copy() Shallow copy d2 = d.copy()

Iterating Over Dictionaries

person = {"name": "Alice", "age": 25, "city": "NYC"}

# Iterate over keys (default)
for key in person:
    print(key)  # name, age, city

# Iterate over values
for value in person.values():
    print(value)  # Alice, 25, NYC

# Iterate over both
for key, value in person.items():
    print(f"{key}: {value}")

Dictionary Comprehensions

# Basic
squares = {x: x**2 for x in range(5)}
# {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

# With condition
even_squares = {x: x**2 for x in range(10) if x % 2 == 0}
# {0: 0, 2: 4, 4: 16, 6: 36, 8: 64}

# From two lists
keys = ["a", "b", "c"]
values = [1, 2, 3]
combined = {k: v for k, v in zip(keys, values)}
# {"a": 1, "b": 2, "c": 3}

# Invert a dictionary
original = {"a": 1, "b": 2, "c": 3}
inverted = {v: k for k, v in original.items()}
# {1: "a", 2: "b", 3: "c"}

Nested Dictionaries

# Nested structure
users = {
    "alice": {
        "email": "alice@example.com",
        "age": 25,
        "hobbies": ["reading", "coding"]
    },
    "bob": {
        "email": "bob@example.com",
        "age": 30,
        "hobbies": ["gaming", "music"]
    }
}

# Access nested values
print(users["alice"]["email"])       # alice@example.com
print(users["bob"]["hobbies"][0])    # gaming

# Safe nested access
alice_age = users.get("alice", {}).get("age", "Unknown")

Checking Keys

person = {"name": "Alice", "age": 25}

# Check if key exists
"name" in person      # True
"country" in person   # False

# Check if key doesn't exist
"country" not in person  # True

Common Patterns

Count occurrences

text = "hello"
counts = {}
for char in text:
    counts[char] = counts.get(char, 0) + 1
# {'h': 1, 'e': 1, 'l': 2, 'o': 1}

# Or use Counter
from collections import Counter
counts = Counter(text)

Group items

words = ["apple", "banana", "apricot", "blueberry", "cherry"]
by_letter = {}
for word in words:
    first = word[0]
    if first not in by_letter:
        by_letter[first] = []
    by_letter[first].append(word)
# {'a': ['apple', 'apricot'], 'b': ['banana', 'blueberry'], 'c': ['cherry']}

Merge dictionaries

d1 = {"a": 1, "b": 2}
d2 = {"b": 3, "c": 4}

# Python 3.9+
merged = d1 | d2  # {"a": 1, "b": 3, "c": 4}

# Python 3.5+
merged = {**d1, **d2}

Common Mistakes

1. Modifying while iterating

d = {"a": 1, "b": 2, "c": 3}

# ❌ RuntimeError
for key in d:
    if d[key] < 2:
        del d[key]

# ✅ Create list of keys first
for key in list(d.keys()):
    if d[key] < 2:
        del d[key]

2. Using mutable keys

# ❌ Lists can't be keys (not hashable)
d = {[1, 2]: "value"}  # TypeError

# ✅ Use tuples instead
d = {(1, 2): "value"}

3. Missing key errors

d = {"a": 1}
print(d["b"])  # ❌ KeyError

# ✅ Use get() method
print(d.get("b", 0))

Quick Reference

# Create
d = {}
d = {"a": 1, "b": 2}
d = dict(a=1, b=2)

# Access
d["key"]           # Raises KeyError if missing
d.get("key")       # Returns None if missing
d.get("key", 0)    # Returns default if missing

# Modify
d["key"] = value   # Add or update
d.update({...})    # Merge another dict
d.pop("key")       # Remove and return
del d["key"]       # Just remove

# Iterate
for key in d: ...
for value in d.values(): ...
for key, value in d.items(): ...

# Check
"key" in d
"key" not in d

Next Steps

Practice with examples.py, then try exercises.py!