Chapter 8: Dictionaries: Key-Value Pairs ๐Ÿ“–

In the last chapter, you learned about lists โ€” collections where you access items by their position (index 0, 1, 2โ€ฆ). But what if you want to organize data using meaningful labels instead of numbers? What if you want to store a personโ€™s name, age, and email together in a way that makes sense?

Thatโ€™s where dictionaries come in! They let you store data using descriptive keys like "name" or "age" instead of remembering that index 0 is the name and index 1 is the age. This makes your code more readable and powerful.


Introduction to Dictionaries ๐ŸŽฏ

A dictionary is a collection of key-value pairs. Each key acts like a label that points to a value. Think of it like a real dictionary where you look up a word (the key) to find its definition (the value).

Creating Dictionaries

To create a dictionary, use curly braces {} with key-value pairs separated by colons:

# A simple dictionary
student = {
    "name": "Jordan",
    "age": 14,
    "grade": "9th"
}

Each entry has:

  • A key (like "name", "age", "grade")
  • A colon :
  • A value (like "Jordan", 14, "9th")
  • A comma separating each pair (except the last one)

Keys are usually strings, but values can be any data type โ€” strings, numbers, booleans, lists, or even other dictionaries!

More Examples

# Game character stats
character = {
    "name": "DragonSlayer",
    "health": 100,
    "mana": 50,
    "level": 12,
    "equipped": True
}

# Product information
product = {
    "name": "Gaming Mouse",
    "price": 49.99,
    "in_stock": True,
    "quantity": 15
}

# Empty dictionary
empty_dict = {}

Why Use Dictionaries?

Compare these two approaches:

Using a list (confusing):

student = ["Jordan", 14, "9th", "Math"]
# Is index 0 the name or age? Hard to remember!
print(student[0])  # What does this represent?

Using a dictionary (clear):

student = {
    "name": "Jordan",
    "age": 14,
    "grade": "9th",
    "favorite_subject": "Math"
}
print(student["name"])  # Obviously the name!

Dictionaries make your code self-documenting and much easier to understand.

Displaying Dictionaries

You can print an entire dictionary:

player = {"name": "Alex", "score": 1250, "level": 5}
print(player)
# Shows: {'name': 'Alex', 'score': 1250, 'level': 5}

Accessing Dictionary Values ๐Ÿ”

Unlike lists where you use numeric indices, dictionaries use keys to access values. This makes your code much more readable.

Using Keys

To access a value, use square brackets with the key:

student = {
    "name": "Jordan",
    "age": 14,
    "grade": "9th",
    "gpa": 3.8
}

print(student["name"])   # Shows: Jordan
print(student["age"])    # Shows: 14
print(student["gpa"])    # Shows: 3.8

Keys Are Case-Sensitive

Make sure your key matches exactly:

player = {"name": "Alex", "score": 1250}

print(player["name"])   # Works!
print(player["Name"])   # ERROR: KeyError: 'Name'

"name" and "Name" are different keys.

Using .get() Method

If you try to access a key that doesnโ€™t exist, Python raises a KeyError:

student = {"name": "Jordan", "age": 14}
print(student["email"])  # ERROR: KeyError: 'email'

The .get() method provides a safer alternative. It returns None if the key doesnโ€™t exist (or a default value you specify):

student = {"name": "Jordan", "age": 14}

# Returns None if key doesn't exist
email = student.get("email")
print(email)  # Shows: None

# Return a default value if key doesn't exist
email = student.get("email", "No email on file")
print(email)  # Shows: No email on file

# Key exists - works normally
name = student.get("name")
print(name)  # Shows: Jordan

This is especially useful when youโ€™re not sure if a key exists.

Using Dictionary Values

Once you access a value, you can use it like any other variable:

product = {
    "name": "Laptop",
    "price": 999.99,
    "tax_rate": 0.08
}

price = product["price"]
tax = price * product["tax_rate"]
total = price + tax

print(f"Product: {product['name']}")
print(f"Price: ${price:.2f}")
print(f"Tax: ${tax:.2f}")
print(f"Total: ${total:.2f}")

Checking if a Key Exists

Use the in operator to check if a key exists before accessing it:

student = {"name": "Jordan", "age": 14, "grade": "9th"}

if "email" in student:
    print(student["email"])
else:
    print("Email not found")

if "name" in student:
    print(f"Student name: {student['name']}")

Adding and Updating Entries โœ๏ธ

Dictionaries are mutable, meaning you can change them after creation. You can add new key-value pairs or update existing ones.

Adding New Entries

To add a new key-value pair, simply assign a value to a new key:

student = {
    "name": "Jordan",
    "age": 14
}

print(student)  # Shows: {'name': 'Jordan', 'age': 14}

# Add new entries
student["grade"] = "9th"
student["gpa"] = 3.8
student["email"] = "jordan@example.com"

print(student)
# Shows: {'name': 'Jordan', 'age': 14, 'grade': '9th', 'gpa': 3.8, 'email': 'jordan@example.com'}

If the key already exists, it updates the value. If it doesnโ€™t, it creates a new entry.

Updating Existing Entries

To update a value, assign a new value to an existing key:

player = {
    "name": "DragonSlayer",
    "health": 100,
    "score": 1000
}

print(f"Initial score: {player['score']}")

# Take damage
player["health"] -= 25
print(f"Health after damage: {player['health']}")

# Earn points
player["score"] += 500
print(f"New score: {player['score']}")

Using .update() Method

The .update() method adds or updates multiple entries at once:

student = {
    "name": "Jordan",
    "age": 14
}

# Update multiple fields
student.update({
    "age": 15,           # Update existing
    "grade": "10th",     # Add new
    "honor_roll": True   # Add new
})

print(student)

This is convenient when you have several updates to make.

Practical Example: Character Stats

# Initialize character
character = {
    "name": "Warrior",
    "level": 1,
    "health": 100,
    "mana": 50,
    "experience": 0
}

print("=== Character Created ===")
print(f"Name: {character['name']}")
print(f"Level: {character['level']}")
print()

# Character gains experience
print("Character completes a quest!")
character["experience"] += 150

# Level up when experience reaches 100
if character["experience"] >= 100:
    character["level"] += 1
    character["health"] += 20
    character["mana"] += 10
    print("๐ŸŽ‰ Level Up!")

print(f"Level: {character['level']}")
print(f"Health: {character['health']}")
print(f"Experience: {character['experience']}")

Removing Entries ๐Ÿ—‘๏ธ

Python provides several ways to remove entries from dictionaries.

Using del Statement

Remove a key-value pair by key:

student = {
    "name": "Jordan",
    "age": 14,
    "temp_id": "TMP123",
    "grade": "9th"
}

del student["temp_id"]  # Remove the temporary ID
print(student)
# Shows: {'name': 'Jordan', 'age': 14, 'grade': '9th'}

Using .pop() Method

The .pop() method removes a key and returns its value:

inventory = {
    "sword": 1,
    "shield": 1,
    "potion": 5
}

# Use a potion
potions_left = inventory.pop("potion")
print(f"Used 1 potion, {potions_left} total")
inventory["potion"] = potions_left - 1

print(inventory)

You can provide a default value if the key might not exist:

score = game_data.pop("bonus", 0)  # Returns 0 if "bonus" doesn't exist

Using .clear() Method

Remove all entries but keep the dictionary:

cart = {"item1": "Book", "item2": "Pen", "item3": "Notebook"}
cart.clear()
print(cart)  # Shows: {}

Looping Through Dictionaries ๐Ÿ”

Dictionaries are incredibly powerful when combined with loops. You can iterate over keys, values, or both.

Looping Over Keys

By default, looping over a dictionary gives you the keys:

grades = {
    "Math": 90,
    "Science": 85,
    "English": 92,
    "History": 88
}

for subject in grades:
    print(subject)

Output:

Math
Science
English
History

You can also explicitly use .keys():

for subject in grades.keys():
    print(subject)

Looping Over Values

To get just the values, use .values():

grades = {
    "Math": 90,
    "Science": 85,
    "English": 92,
    "History": 88
}

for grade in grades.values():
    print(f"Grade: {grade}")

Output:

Grade: 90
Grade: 85
Grade: 92
Grade: 88

Looping Over Key-Value Pairs

To get both keys and values, use .items():

grades = {
    "Math": 90,
    "Science": 85,
    "English": 92,
    "History": 88
}

for subject, grade in grades.items():
    print(f"{subject}: {grade}")

Output:

Math: 90
Science: 85
English: 92
History: 88

This is the most common and useful pattern.

Practical Examples

Example 1: Calculate total and average

prices = {
    "laptop": 999.99,
    "mouse": 24.99,
    "keyboard": 79.99,
    "monitor": 299.99
}

total = 0
for item, price in prices.items():
    print(f"{item}: ${price:.2f}")
    total += price

print(f"\nTotal: ${total:.2f}")
average = total / len(prices)
print(f"Average price: ${average:.2f}")

Example 2: Find highest value

scores = {
    "Alice": 95,
    "Bob": 87,
    "Charlie": 92,
    "Diana": 98
}

highest_name = ""
highest_score = 0

for name, score in scores.items():
    if score > highest_score:
        highest_score = score
        highest_name = name

print(f"Highest score: {highest_name} with {highest_score}")

Example 3: Filter and display

inventory = {
    "sword": 1,
    "shield": 1,
    "potion": 15,
    "gold_coin": 250,
    "mana_potion": 8
}

print("Items with quantity > 5:")
for item, quantity in inventory.items():
    if quantity > 5:
        print(f"  {item}: {quantity}")

Example 4: Count and categorize

ages = {
    "Alice": 12,
    "Bob": 15,
    "Charlie": 11,
    "Diana": 14,
    "Eve": 16
}

teens = 0
for name, age in ages.items():
    if age >= 13:
        print(f"{name} is a teenager ({age})")
        teens += 1

print(f"\nTotal teenagers: {teens}")

Dictionary Helpers ๐Ÿ› ๏ธ

Python provides several useful functions and methods for working with dictionaries.

The len() Function

Get the number of key-value pairs:

student = {
    "name": "Jordan",
    "age": 14,
    "grade": "9th",
    "gpa": 3.8
}

count = len(student)
print(f"The dictionary has {count} entries")  # Shows: 4 entries

Getting All Keys or Values

Convert keys or values to lists:

grades = {"Math": 90, "Science": 85, "English": 92}

subjects = list(grades.keys())
scores = list(grades.values())

print(f"Subjects: {subjects}")
print(f"Scores: {scores}")

Copying Dictionaries

Create a copy with .copy():

original = {"name": "Alex", "score": 100}
backup = original.copy()

original["score"] = 200

print(f"Original: {original}")  # Shows: {'name': 'Alex', 'score': 200}
print(f"Backup: {backup}")      # Shows: {'name': 'Alex', 'score': 100}

Without .copy(), both variables would point to the same dictionary.

Merging Dictionaries

Combine two dictionaries:

defaults = {"theme": "dark", "language": "en", "notifications": True}
user_prefs = {"theme": "light", "font_size": 14}

# Python 3.9+: Use the | operator
settings = defaults | user_prefs
print(settings)
# Shows: {'theme': 'light', 'language': 'en', 'notifications': True, 'font_size': 14}

# Alternative: use .update()
all_settings = defaults.copy()
all_settings.update(user_prefs)

Checking for Keys

We already saw in, but here are more examples:

user = {"username": "alex123", "email": "alex@example.com"}

# Check if key exists
if "username" in user:
    print(f"Username: {user['username']}")

# Check if key doesn't exist
if "phone" not in user:
    print("No phone number on file")

Nested Dictionaries ๐Ÿ—๏ธ

Dictionaries can contain other dictionaries, allowing you to create complex data structures.

Basic Nesting

student = {
    "name": "Jordan",
    "age": 14,
    "grades": {
        "Math": 90,
        "Science": 85,
        "English": 92
    },
    "contact": {
        "email": "jordan@example.com",
        "phone": "555-0123"
    }
}

# Access nested values
print(student["name"])                    # Shows: Jordan
print(student["grades"]["Math"])          # Shows: 90
print(student["contact"]["email"])        # Shows: jordan@example.com

Multiple Entries

# Multiple students
students = {
    "student1": {
        "name": "Alice",
        "grade": 90,
        "year": "10th"
    },
    "student2": {
        "name": "Bob",
        "grade": 85,
        "year": "9th"
    },
    "student3": {
        "name": "Charlie",
        "grade": 92,
        "year": "10th"
    }
}

# Loop through nested dictionaries
for student_id, info in students.items():
    print(f"{student_id}:")
    print(f"  Name: {info['name']}")
    print(f"  Grade: {info['grade']}")
    print(f"  Year: {info['year']}")
    print()

Quick Recap ๐ŸŽฏ

Youโ€™ve mastered dictionaries in Python:

  • Create dictionaries with {} and key-value pairs
  • Access values using keys in square brackets or .get()
  • Add and update entries by assigning to keys
  • Remove entries with del, .pop(), or .clear()
  • Loop through keys, values, or items with .items()
  • Use helpers like len(), in, .keys(), and .values()
  • Nest dictionaries to create complex data structures

Dictionaries make organizing related data intuitive and efficient!


Hands-On Mini Project: Contact Book ๐Ÿ“‡

Letโ€™s build a contact management system that uses dictionaries to store and organize contact information.

Your Mission

Create an interactive contact book where users can:

  1. Add new contacts
  2. View all contacts
  3. Search for a contact
  4. Update contact information
  5. Delete a contact
  6. Exit the program

Example Solution

print("=" * 60)
print("              CONTACT BOOK MANAGER")
print("=" * 60)
print()

# Initialize empty contact book
contacts = {}

# Main program loop
running = True

while running:
    # Display menu
    print("\nWhat would you like to do?")
    print("1. Add a contact")
    print("2. View all contacts")
    print("3. Search for a contact")
    print("4. Update a contact")
    print("5. Delete a contact")
    print("6. Exit")
    
    choice = input("\nEnter your choice (1-6): ")
    print()
    
    # Add a contact
    if choice == "1":
        print("=== Add New Contact ===")
        name = input("Enter name: ").strip()
        
        if name in contacts:
            print(f"โŒ {name} already exists!")
        else:
            phone = input("Enter phone number: ").strip()
            email = input("Enter email: ").strip()
            
            contacts[name] = {
                "phone": phone,
                "email": email
            }
            
            print(f"โœ“ Added {name} to contacts!")
    
    # View all contacts
    elif choice == "2":
        if len(contacts) == 0:
            print("Your contact book is empty.")
        else:
            print("=" * 60)
            print("ALL CONTACTS:")
            print("=" * 60)
            
            for name, info in contacts.items():
                print(f"\n๐Ÿ“‡ {name}")
                print(f"   Phone: {info['phone']}")
                print(f"   Email: {info['email']}")
            
            print("\n" + "=" * 60)
            print(f"Total contacts: {len(contacts)}")
    
    # Search for a contact
    elif choice == "3":
        search_name = input("Enter name to search: ").strip()
        
        if search_name in contacts:
            info = contacts[search_name]
            print("\n" + "=" * 60)
            print(f"๐Ÿ“‡ {search_name}")
            print(f"   Phone: {info['phone']}")
            print(f"   Email: {info['email']}")
            print("=" * 60)
        else:
            print(f"โŒ {search_name} not found in contacts.")
    
    # Update a contact
    elif choice == "4":
        update_name = input("Enter name to update: ").strip()
        
        if update_name not in contacts:
            print(f"โŒ {update_name} not found in contacts.")
        else:
            print(f"\nCurrent information for {update_name}:")
            print(f"Phone: {contacts[update_name]['phone']}")
            print(f"Email: {contacts[update_name]['email']}")
            print()
            
            print("Enter new information (press Enter to keep current):")
            new_phone = input(f"Phone [{contacts[update_name]['phone']}]: ").strip()
            new_email = input(f"Email [{contacts[update_name]['email']}]: ").strip()
            
            # Update only if new value provided
            if new_phone:
                contacts[update_name]['phone'] = new_phone
            if new_email:
                contacts[update_name]['email'] = new_email
            
            print(f"โœ“ Updated {update_name}!")
    
    # Delete a contact
    elif choice == "5":
        delete_name = input("Enter name to delete: ").strip()
        
        if delete_name not in contacts:
            print(f"โŒ {delete_name} not found in contacts.")
        else:
            confirm = input(f"Are you sure you want to delete {delete_name}? (yes/no): ")
            if confirm.lower() == "yes":
                contacts.pop(delete_name)
                print(f"โœ“ Deleted {delete_name} from contacts.")
            else:
                print("Cancelled.")
    
    # Exit
    elif choice == "6":
        print(f"You have {len(contacts)} contact(s) in your book.")
        print("\nThanks for using Contact Book Manager!")
        print("Goodbye! ๐Ÿ‘‹")
        running = False
    
    # Invalid choice
    else:
        print("โŒ Invalid choice. Please enter 1-6.")

print()
print("=" * 60)

Challenge Yourself

Enhance your contact book with these features:

  1. Multiple phone numbers โ€” Store home, work, and mobile numbers
  2. Address information โ€” Add street, city, state, zip
  3. Categories โ€” Tag contacts as family, friends, work, etc.
  4. Birthday tracking โ€” Store and display birthdays
  5. Favorites โ€” Mark certain contacts as favorites
  6. Export contacts โ€” Display all contacts in a formatted way to copy
  7. Advanced search โ€” Search by phone number or email, not just name
  8. Sort contacts โ€” Display contacts alphabetically
  9. Notes field โ€” Add custom notes to each contact
  10. Statistics โ€” Show how many contacts in each category

Tips for Building

  • Use .strip() on input to remove extra spaces
  • Check if a contact exists before trying to update or delete
  • Validate input (e.g., ensure email contains @)
  • Use nested dictionaries for complex contact information
  • Give clear feedback after each operation
  • Consider using .get() for safer access to nested values

Whatโ€™s Next?

In the next chapter, youโ€™ll learn about functions โ€” how to create your own reusable blocks of code! Youโ€™ll discover how to organize your programs better and avoid repeating yourself.

Get ready to write cleaner, more organized code!


Excellent work! Dictionaries are incredibly powerful for organizing real-world data!