Teacher's Guide

Chapter 8: Using Dictionaries

Teaching Objectives

By the end of this chapter, students should:

  • Understand what dictionaries are and how they differ from lists
  • Know how to create and manipulate dictionaries in Python
  • Master accessing, adding, modifying, and deleting dictionary elements
  • Learn common dictionary methods and operations
  • Apply dictionaries to solve real-world problems

Preparation

Before teaching this chapter, ensure:

  • Students understand basic Python data types and operators
  • Students are comfortable with lists and basic data structures
  • Your teaching environment allows for interactive coding demonstrations
  • You have prepared simple examples of dictionary usage

Lesson Overview

1. Introduction to Dictionaries (15 minutes)

Start by explaining what dictionaries are:

  • Dictionaries are collections of key-value pairs
  • Each key maps to a value (like a real dictionary maps words to definitions)
  • Keys must be unique and immutable (typically strings, numbers, or tuples)
  • Values can be any data type (strings, numbers, lists, other dictionaries, etc.)
  • Dictionaries are unordered in Python versions before 3.7 (ordered from 3.7 onward)

Basic dictionary creation:

# Creating a simple dictionary
student = {
    "name": "Alice",
    "age": 15,
    "grade": 9,
    "subjects": ["Math", "Science", "English"]
}

# Display the dictionary
print(student)

Alternative creation methods:

# Using dict() constructor
person = dict(name="Bob", age=25, city="New York")
print(person)

# Creating an empty dictionary and adding items
pet = {}
pet["type"] = "Dog"
pet["name"] = "Buddy"
pet["age"] = 3
print(pet)

Teaching points:

  • Dictionary keys are written inside curly braces {}
  • Each key is followed by a colon : and then its value
  • Key-value pairs are separated by commas
  • We can create dictionaries using different methods
  • Dictionaries are mutable (can be changed)

2. Accessing Dictionary Elements (20 minutes)

Explain how to retrieve values from dictionaries:

# Accessing values using keys
student = {
    "name": "Alice",
    "age": 15,
    "grade": 9,
    "subjects": ["Math", "Science", "English"]
}

print(f"Name: {student['name']}")
print(f"Age: {student['age']}")
print(f"Subjects: {student['subjects']}")

# Accessing list items within dictionaries
print(f"First subject: {student['subjects'][0]}")

Using get() method:

# Using get() method (safer way to access values)
name = student.get("name")
print(f"Name: {name}")

# Providing default value with get()
hobby = student.get("hobby", "No hobby listed")
print(f"Hobby: {hobby}")  # Uses default value

# This would cause an error:
# print(student["hobby"])  # KeyError

Checking if a key exists:

# Check if key exists in dictionary
if "age" in student:
    print(f"The student is {student['age']} years old")

if "address" not in student:
    print("No address provided")

Teaching points:

  • Access values by using square brackets [] with the key
  • The get() method provides a safer way to access values
  • Use get(key, default) to provide a default value if the key doesn't exist
  • Use in and not in operators to check if a key exists
  • Accessing a non-existent key with square brackets causes a KeyError

3. Modifying Dictionaries (15 minutes)

Show how to modify dictionary contents:

# Modifying a dictionary
student = {
    "name": "Alice",
    "age": 15,
    "grade": 9
}

# Changing values
student["age"] = 16
print(f"Updated age: {student['age']}")

# Adding new key-value pairs
student["school"] = "Lincoln High"
print(f"Added school: {student['school']}")

# Adding a list as a value
student["subjects"] = ["Math", "Science", "History"]
print(f"Added subjects: {student['subjects']}")

# Modify a list value
student["subjects"].append("Art")
print(f"Updated subjects: {student['subjects']}")

# Removing a key-value pair
del student["grade"]
print("After removing grade:", student)

# Alternative way to remove (and get the value)
school = student.pop("school")
print(f"Removed school: {school}")
print("After pop:", student)

Teaching points:

  • Assign a new value to an existing key to update it
  • Add a new key-value pair by simply assigning a value to a new key
  • Remove keys using del or pop()
  • pop() returns the value being removed
  • Dictionary values can be complex data types like lists

4. Dictionary Methods (20 minutes)

Introduce useful dictionary methods:

# Create a sample dictionary
book = {
    "title": "Harry Potter",
    "author": "J.K. Rowling",
    "year": 1997,
    "pages": 223
}

# Get all keys
keys = book.keys()
print("All keys:", keys)
print("Keys list:", list(keys))

# Get all values
values = book.values()
print("All values:", values)
print("Values list:", list(values))

# Get all key-value pairs as tuples
items = book.items()
print("All items:", items)
print("Items list:", list(items))

# Clear a dictionary
book_copy = book.copy()  # Make a copy first
book_copy.clear()
print("Cleared dictionary:", book_copy)

# Update with another dictionary
book.update({"publisher": "Bloomsbury", "pages": 230})
print("After update:", book)

# setdefault - set a key if it doesn't exist
current_author = book.setdefault("author", "Unknown")
new_genre = book.setdefault("genre", "Fantasy")
print(f"Current author: {current_author}")
print(f"New genre: {new_genre}")
print("After setdefault:", book)

Teaching points:

  • keys(), values(), and items() return special "view" objects
  • These views reflect changes to the dictionary
  • Convert them to lists if needed
  • copy() creates a shallow copy of a dictionary
  • clear() removes all items
  • update() adds or updates multiple key-value pairs
  • setdefault() adds a key with a default value if the key doesn't exist

5. Dictionary Loops (15 minutes)

Demonstrate how to iterate through dictionaries:

# Sample dictionary
student = {
    "name": "Alice",
    "age": 16,
    "grade": 10,
    "subjects": ["Math", "Science", "English", "History"]
}

# Looping through keys
print("Keys in the dictionary:")
for key in student:
    print(key)

# Alternative way to loop through keys
print("\nKeys (alternative method):")
for key in student.keys():
    print(key)

# Looping through values
print("\nValues in the dictionary:")
for value in student.values():
    print(value)

# Looping through key-value pairs
print("\nKey-value pairs:")
for key, value in student.items():
    print(f"{key}: {value}")

# Accessing both keys and values
print("\nAnother way to access both:")
for key in student:
    print(f"{key}: {student[key]}")

Teaching points:

  • By default, iterating a dictionary gives its keys
  • Use values() to iterate through values
  • Use items() to get key-value pairs as tuples
  • Unpacking tuples with key, value syntax is convenient
  • Dictionaries are efficient for lookups and storing related data

6. Nested Dictionaries (20 minutes)

Explain how to work with nested dictionaries:

# Nested dictionary
school = {
    "students": {
        "Alice": {
            "grade": 10,
            "subjects": ["Math", "Science", "English"]
        },
        "Bob": {
            "grade": 9,
            "subjects": ["History", "Art", "Math"]
        }
    },
    "teachers": {
        "Mr. Smith": {
            "subject": "Math",
            "room": 101
        },
        "Ms. Johnson": {
            "subject": "Science",
            "room": 102
        }
    }
}

# Accessing nested values
print(f"Alice's grade: {school['students']['Alice']['grade']}")
print(f"Bob's subjects: {school['students']['Bob']['subjects']}")
print(f"Ms. Johnson's room: {school['teachers']['Ms. Johnson']['room']}")

# Modifying nested values
school['students']['Alice']['grade'] = 11
print(f"Alice's updated grade: {school['students']['Alice']['grade']}")

# Adding a new student
school['students']['Charlie'] = {
    "grade": 10,
    "subjects": ["Physics", "Computer Science"]
}

# Looping through nested dictionaries
print("\nAll students:")
for student_name, student_info in school['students'].items():
    print(f"\n{student_name}:")
    print(f"  Grade: {student_info['grade']}")
    print(f"  Subjects: {', '.join(student_info['subjects'])}")

Teaching points:

  • Dictionaries can contain other dictionaries as values
  • Nested dictionaries allow for hierarchical data organization
  • Access nested values by chaining multiple keys in square brackets
  • Traversing deep nested structures requires careful organization
  • Nested dictionaries are useful for complex data representation

7. Dictionary Comprehensions (15 minutes)

Introduce dictionary comprehensions:

# Creating dictionaries with comprehensions
# Basic example: squares of numbers
squares = {x: x**2 for x in range(1, 6)}
print("Squares:", squares)

# Creating from two lists
fruits = ["apple", "banana", "cherry"]
prices = [1.2, 0.9, 2.5]
fruit_prices = {fruit: price for fruit, price in zip(fruits, prices)}
print("Fruit prices:", fruit_prices)

# Conditional dictionary comprehension
even_squares = {x: x**2 for x in range(10) if x % 2 == 0}
print("Even squares:", even_squares)

# Transforming an existing dictionary
fruit_inventory = {"apple": 10, "banana": 15, "cherry": 8}
fruit_status = {
    fruit: ("low" if count < 10 else "good") 
    for fruit, count in fruit_inventory.items()
}
print("Fruit status:", fruit_status)

Teaching points:

  • Dictionary comprehensions provide a concise way to create dictionaries
  • The syntax is {key_expr: value_expr for item in iterable}
  • We can add conditions with if statements
  • For generating keys and values from two sequences, zip() is useful
  • Comprehensions can transform data from one form to another

8. Practical Applications (20 minutes)

Show real-world applications of dictionaries:

Counting word frequency:

# Count word frequency in a text
text = "the quick brown fox jumps over the lazy dog the fox was quick"
words = text.lower().split()

word_count = {}
for word in words:
    if word in word_count:
        word_count[word] += 1
    else:
        word_count[word] = 1

print("Word frequency:")
for word, count in word_count.items():
    print(f"{word}: {count}")

# Alternative approach using get()
word_count2 = {}
for word in words:
    word_count2[word] = word_count2.get(word, 0) + 1

print("\nUsing get() method:")
for word, count in sorted(word_count2.items()):
    print(f"{word}: {count}")

Simple contact manager:

# Simple contact manager
contacts = {}

def add_contact(name, phone, email=None):
    contacts[name] = {"phone": phone, "email": email}
    print(f"Added contact: {name}")

def display_contacts():
    if not contacts:
        print("No contacts found.")
        return
        
    print("\nContacts List:")
    print("-" * 40)
    for name, info in contacts.items():
        email_display = info["email"] if info["email"] else "N/A"
        print(f"Name: {name}")
        print(f"Phone: {info['phone']}")
        print(f"Email: {email_display}")
        print("-" * 40)

def find_contact(name):
    contact = contacts.get(name)
    if contact:
        print(f"\nFound contact: {name}")
        print(f"Phone: {contact['phone']}")
        if contact['email']:
            print(f"Email: {contact['email']}")
    else:
        print(f"\nNo contact found with name: {name}")

# Test the contact manager
add_contact("Alice", "555-1234", "[email protected]")
add_contact("Bob", "555-5678")
add_contact("Charlie", "555-9012", "[email protected]")

display_contacts()
find_contact("Bob")
find_contact("David")

Teaching points:

  • Dictionaries are ideal for counting and categorizing items
  • They're useful for representing complex real-world data
  • Applications include contact lists, inventory systems, game state tracking
  • Dictionaries allow for efficient lookups by key

9. Guided Practice (20 minutes)

Have students create these programs:

  1. Student grades tracker:

    # Create a program to track student grades
    
    # Initialize an empty dictionary to store student grades
    student_grades = {}
    
    # Function to add a new student
    def add_student(name):
        if name in student_grades:
            print(f"{name} is already in the system.")
        else:
            student_grades[name] = {}
            print(f"Added {name} to the system.")
    
    # Function to add a grade for a subject
    def add_grade(name, subject, grade):
        if name not in student_grades:
            print(f"Error: {name} not found.")
            return
            
        student_grades[name][subject] = grade
        print(f"Added {grade} for {name} in {subject}.")
    
    # Function to calculate average grade for a student
    def calculate_average(name):
        if name not in student_grades:
            print(f"Error: {name} not found.")
            return None
            
        grades = student_grades[name].values()
        if not grades:
            print(f"{name} has no grades yet.")
            return None
            
        average = sum(grades) / len(grades)
        return average
    
    # Function to display a student's grades
    def display_student(name):
        if name not in student_grades:
            print(f"Error: {name} not found.")
            return
            
        print(f"\nGrades for {name}:")
        if not student_grades[name]:
            print("No grades recorded yet.")
            return
            
        for subject, grade in student_grades[name].items():
            print(f"{subject}: {grade}")
            
        average = calculate_average(name)
        if average is not None:
            print(f"Average: {average:.2f}")
    
    # Test the program
    add_student("Alice")
    add_student("Bob")
    
    add_grade("Alice", "Math", 95)
    add_grade("Alice", "Science", 88)
    add_grade("Alice", "English", 92)
    add_grade("Bob", "Math", 85)
    add_grade("Bob", "Science", 90)
    
    display_student("Alice")
    display_student("Bob")
    
  2. Simple inventory system:

    # Create a simple inventory management system
    
    # Initialize inventory
    inventory = {
        "apple": {"price": 1.0, "quantity": 10},
        "banana": {"price": 0.5, "quantity": 20},
        "orange": {"price": 1.2, "quantity": 15}
    }
    
    # Function to display inventory
    def display_inventory():
        print("\nCurrent Inventory:")
        print("-" * 50)
        print(f"{'Item':<10}{'Price':>10}{'Quantity':>15}{'Value':>15}")
        print("-" * 50)
        
        total_value = 0
        for item, info in inventory.items():
            value = info["price"] * info["quantity"]
            total_value += value
            print(f"{item:<10}${info['price']:>9.2f}{info['quantity']:>15}${value:>14.2f}")
        
        print("-" * 50)
        print(f"{'Total Value:':<35}${total_value:>14.2f}")
    
    # Function to add or update an item
    def update_item(item, price, quantity):
        if item in inventory:
            inventory[item]["price"] = price
            inventory[item]["quantity"] = quantity
            print(f"Updated {item} in inventory.")
        else:
            inventory[item] = {"price": price, "quantity": quantity}
            print(f"Added {item} to inventory.")
    
    # Function to remove an item
    def remove_item(item):
        if item in inventory:
            del inventory[item]
            print(f"Removed {item} from inventory.")
        else:
            print(f"Error: {item} not in inventory.")
    
    # Function to check if an item is in stock
    def check_stock(item, quantity=1):
        if item not in inventory:
            return False
        
        return inventory[item]["quantity"] >= quantity
    
    # Test the inventory system
    display_inventory()
    
    update_item("apple", 1.2, 15)  # Update existing item
    update_item("grape", 2.0, 8)   # Add new item
    remove_item("orange")
    
    print(f"\nApples in stock for 10 units: {check_stock('apple', 10)}")
    print(f"Bananas in stock for 25 units: {check_stock('banana', 25)}")
    
    display_inventory()
    

10. Challenge Activities (15 minutes)

For more advanced students:

  1. Menu-based dictionary manipulation:

    # Create a menu-based program to manipulate a dictionary
    
    def show_menu():
        print("\nDictionary Operations")
        print("---------------------")
        print("1. Add/Update an entry")
        print("2. Delete an entry")
        print("3. Find an entry")
        print("4. Display all entries")
        print("5. Clear all entries")
        print("6. Exit")
        return input("Enter your choice (1-6): ")
    
    # Initialize an empty dictionary
    data = {}
    
    # Main program loop
    while True:
        choice = show_menu()
        
        if choice == "1":
            key = input("Enter key: ")
            value = input("Enter value: ")
            data[key] = value
            print(f"Added/Updated: {key} -> {value}")
            
        elif choice == "2":
            key = input("Enter key to delete: ")
            if key in data:
                del data[key]
                print(f"Deleted: {key}")
            else:
                print(f"Error: {key} not found")
                
        elif choice == "3":
            key = input("Enter key to find: ")
            if key in data:
                print(f"Found: {key} -> {data[key]}")
            else:
                print(f"Error: {key} not found")
                
        elif choice == "4":
            if not data:
                print("Dictionary is empty")
            else:
                print("\nCurrent Entries:")
                for key, value in data.items():
                    print(f"{key}: {value}")
                    
        elif choice == "5":
            confirm = input("Are you sure you want to clear all entries? (y/n): ")
            if confirm.lower() == 'y':
                data.clear()
                print("Dictionary cleared")
                
        elif choice == "6":
            print("Exiting program...")
            break
            
        else:
            print("Invalid choice. Please enter a number from 1 to 6.")
    
  2. Morse code translator:

    # Create a Morse code translator using dictionaries
    
    # Morse code dictionary
    morse_code = {
        'A': '.-', 'B': '-...', 'C': '-.-.', 'D': '-..', 'E': '.', 'F': '..-.',
        'G': '--.', 'H': '....', 'I': '..', 'J': '.---', 'K': '-.-', 'L': '.-..',
        'M': '--', 'N': '-.', 'O': '---', 'P': '.--.', 'Q': '--.-', 'R': '.-.',
        'S': '...', 'T': '-', 'U': '..-', 'V': '...-', 'W': '.--', 'X': '-..-',
        'Y': '-.--', 'Z': '--..',
        '0': '-----', '1': '.----', '2': '..---', '3': '...--', '4': '....-',
        '5': '.....', '6': '-....', '7': '--...', '8': '---..', '9': '----.',
        '.': '.-.-.-', ',': '--..--', '?': '..--..', "'": '.----.', '!': '-.-.--',
        '/': '-..-.', '(': '-.--.', ')': '-.--.-', '&': '.-...', ':': '---...',
        ';': '-.-.-.', '=': '-...-', '+': '.-.-.', '-': '-....-', '_': '..--.-',
        '"': '.-..-.', '$': '...-..-', '@': '.--.-.'
    }
    
    # Create reverse lookup dictionary
    morse_to_char = {value: key for key, value in morse_code.items()}
    
    def text_to_morse(text):
        """Convert text to Morse code"""
        result = []
        for char in text.upper():
            if char == ' ':
                # Add space between words (conventionally 7 units)
                result.append('   ')
            elif char in morse_code:
                # Add the morse code and a space between characters
                result.append(morse_code[char] + ' ')
            else:
                # Handle unknown characters
                result.append('? ')
        
        return ''.join(result)
    
    def morse_to_text(morse):
        """Convert Morse code to text"""
        # Split by spaces (conventionally 3 spaces between words)
        words = morse.strip().split('   ')
        result = []
        
        for word in words:
            # Split into characters (1 space between morse characters)
            chars = word.split()
            word_result = []
            
            for char in chars:
                if char in morse_to_char:
                    word_result.append(morse_to_char[char])
                else:
                    word_result.append('?')
                    
            result.append(''.join(word_result))
        
        return ' '.join(result)
    
    # Test the translator
    message = "Hello World"
    morse = text_to_morse(message)
    print(f"Original: {message}")
    print(f"Morse: {morse}")
    print(f"Decoded: {morse_to_text(morse)}")
    
    # Try with custom input
    custom_message = input("\nEnter a message to convert to Morse code: ")
    custom_morse = text_to_morse(custom_message)
    print(f"Morse: {custom_morse}")
    print(f"Decoded: {morse_to_text(custom_morse)}")
    

11. Review and Discussion (10 minutes)

  • Review the key concepts covered
  • Ask students to explain in their own words:
    • What is a dictionary and when would you use one?
    • How do dictionaries differ from lists?
    • What are some common dictionary methods?
    • How do you iterate through a dictionary?

Common Challenges and Solutions

  • Understanding the key-value concept: Compare to real-world examples like a phonebook (name→number) or a dictionary (word→definition).
  • Forgetting that dictionary keys must be immutable: Remind students that lists and dictionaries can't be used as keys.
  • Confusion about dictionary order: Explain the historical unordered nature and the change in Python 3.7+.
  • KeyError when accessing non-existent keys: Encourage using get() or checking with in first.

Extension Activities

For students who finish early:

  • Have them create a more complex dictionary-based application (e.g., a recipe manager)
  • Challenge them to solve a data organization problem using nested dictionaries
  • Ask them to convert between different data representations using dictionaries

Assessment

Look for these indicators of understanding:

  • Students can create and manipulate dictionaries correctly
  • They can choose appropriate techniques for different dictionary operations
  • They understand common patterns like counting and grouping using dictionaries
  • They can design solutions using dictionaries for complex data

Resources

Chapter 8: Using Dictionaries | Teacher's Guide