Dictionaries
Summary
This chapter introduces Python dictionaries, the powerful key-value data structure. Students will learn to create dictionaries, access and modify values, use essential methods (get, keys, values, items), iterate over dictionaries, and write dictionary comprehensions. The chapter also covers practical patterns including counting, grouping, caching, and understanding hashable keys. Dictionaries are one of Python's most important and frequently used data structures.
Concepts Covered
This chapter covers the following 21 concepts from the learning graph:
- Dictionaries
- Dictionary Creation
- Key-Value Pairs
- Dictionary Access
- Dictionary Methods
- Get Method
- Keys Method
- Values Method
- Items Method
- Dictionary Iteration
- Dictionary Comprehension
- Nested Dictionaries
- Default Values
- Update Method
- Pop Method for Dicts
- Dictionary Merging
- Counting with Dicts
- Grouping with Dicts
- Dictionary as Cache
- Hashable Keys
- Dict vs List Lookup
Prerequisites
This chapter builds on concepts from:
- Chapter 2: Python Fundamentals
- Chapter 4: Control Flow
- Chapter 6: Functions and Modular Design
- Chapter 8: Lists
- Chapter 10: Tuples and Sets
Monty says: Let's code this!
Welcome back, coders! You've already mastered lists, tuples, and sets. Now it's time to unlock one of Python's most powerful data structures: the dictionary. Think of it like a real dictionary — you look up a word and get its definition. Python dictionaries work the same way, except you can look up anything and get anything back. Let's dive in!
What Are Dictionaries?
Have you ever used a real dictionary? You look up a word (like "python") and find its definition ("a large heavy-bodied nonvenomous snake"). You don't start at page 1 and read every entry until you find the word. You jump straight to the right spot. That's incredibly fast.
Dictionaries in Python work the same way. Instead of storing items in a numbered sequence like a list, a dictionary stores key-value pairs — a key that you look up, paired with a value that you get back. The key is like the word you're looking up, and the value is like the definition you find.
Here's why dictionaries matter: they let you store relationships between pieces of data. A student's name maps to their grade. A product code maps to its price. A username maps to their profile. Anywhere you have a "this goes with that" relationship, dictionaries are your best friend.
Creating Dictionaries
Dictionary creation in Python uses curly braces {} with keys and values separated by colons. Let's see a few ways to build one.
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
All three methods above create the same dictionary. Method 1 is the most common — you'll see it everywhere.
Notice that keys and values can be different types. In our student dictionary, the keys are all strings, but the values include a string ("Alice"), an integer (10), and a float (3.8). Python is flexible like that.
Diagram: Dictionary Structure Visualizer
Dictionary Structure Visualizer MicroSim
Type: diagram
sim-id: dictionary-structure
Library: p5.js
Status: Specified
Bloom Level: Understand (L2) Bloom Verb: describe, illustrate
Learning Objective: Students will be able to visualize how a Python dictionary stores key-value pairs and understand the mapping relationship between keys and values.
Purpose: An interactive visualization showing the internal structure of a dictionary as a set of key-value pairs, with arrows mapping each key to its corresponding value.
Layout:
- Left column: Keys displayed as labeled boxes (e.g., "name", "grade", "gpa")
- Right column: Values displayed as labeled boxes (e.g., "Alice", 10, 3.8)
- Arrows connecting each key to its value
- Bottom: A text input for adding new key-value pairs and a button to add them
Interactive elements:
- Hover over a key to highlight the arrow and its corresponding value
- Click "Add Pair" to add a new key-value pair to the visualization
- Click "Remove" on any pair to delete it
- A "Show Code" toggle that displays the Python code that would create the shown dictionary
Color scheme: Keys in blue boxes, values in green boxes, arrows in gray Responsive: Layout adjusts to window width; boxes resize proportionally
Instructional Rationale: Visualizing the mapping relationship between keys and values makes the abstract concept of key-value storage concrete. Interactive add/remove operations let students see how dictionaries grow and change.
Key-Value Pairs
Let's zoom in on key-value pairs, because they're the heart of every dictionary. A key-value pair is a single entry in the dictionary: the key is the label, and the value is the data associated with that label.
1 2 3 4 5 | |
In this phone book dictionary:
"Alice"is a key, and"555-1234"is its value"Bob"is a key, and"555-5678"is its value"Charlie"is a key, and"555-9012"is its value
A few important rules about keys:
- Keys must be unique. You can't have two entries for "Alice." If you assign a new value to an existing key, it overwrites the old one.
- Keys must be immutable. You can use strings, numbers, or tuples as keys — but not lists or other dictionaries. (We'll explain why in the Hashable Keys section.)
- Values can be anything. Strings, numbers, lists, other dictionaries — even functions!
Accessing Dictionary Values
Dictionary access is how you retrieve a value using its key. The most straightforward way is with square brackets.
1 2 3 4 5 | |
You can also modify values or add new key-value pairs using the same bracket notation:
1 2 3 4 5 6 7 8 | |
Monty says: Watch out!
Be careful! If you try to access a key that doesn't exist using square brackets, Python will raise a KeyError. For example, student["age"] would crash your program if "age" isn't a key in the dictionary. Use the get method (covered next) for safer lookups!
1 2 | |
Dictionary Methods
Python dictionary methods give you a toolkit for working with dictionaries without writing everything from scratch. Let's explore the most important ones.
The Get Method
The get method is a safer way to access dictionary values. Instead of crashing with a KeyError when a key doesn't exist, get() returns None (or a default value you specify).
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
Default values are incredibly useful. They let you provide a fallback when a key might not exist, without any extra if/else logic. You'll see this pattern constantly in real-world Python code.
The Keys Method
The keys method returns all the keys in a dictionary. It gives you a special view object that you can loop through or convert to a list.
1 2 3 4 5 6 7 8 | |
The Values Method
The values method does the same thing, but for values instead of keys.
1 2 3 4 5 6 | |
The Items Method
The items method returns both keys and values as a collection of tuples. This is especially powerful when looping.
1 2 3 4 5 6 7 8 9 10 | |
The Update Method
The update method merges another dictionary into the current one. If both dictionaries share a key, the value from the new dictionary wins.
1 2 3 4 5 6 | |
Notice that "grade" was updated from 10 to 11 because new_info had a different value for that key.
The Pop Method for Dicts
The pop method for dicts removes a key-value pair and returns the value. It's like reaching into the dictionary and pulling out an entry.
1 2 3 4 5 6 7 8 9 | |
Dictionary Methods Reference Table
Here's a comprehensive reference for the most common dictionary methods:
| Method | Description | Example | Returns |
|---|---|---|---|
d.get(key, default) |
Safe value lookup | d.get("age", 0) |
Value or default |
d.keys() |
All keys | d.keys() |
dict_keys view |
d.values() |
All values | d.values() |
dict_values view |
d.items() |
All key-value pairs | d.items() |
dict_items view |
d.update(other) |
Merge another dict | d.update({"a": 1}) |
None (modifies d) |
d.pop(key, default) |
Remove and return | d.pop("name") |
Removed value |
d.clear() |
Remove all items | d.clear() |
None |
d.copy() |
Shallow copy | d.copy() |
New dict |
d.setdefault(key, val) |
Get or set default | d.setdefault("x", 0) |
Existing or new value |
key in d |
Check membership | "name" in d |
True / False |
len(d) |
Number of pairs | len(d) |
Integer |
Monty says: Let's debug this together!
Here's a trick that'll save you tons of time: use in to check if a key exists before accessing it. if "name" in student: is clean, readable, and avoids KeyError crashes. But honestly? The get() method is even cleaner for most situations.
Dictionary Iteration
Dictionary iteration means looping through a dictionary's contents. There are several ways to do it, depending on whether you need the keys, the values, or both.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | |
The items() approach is the most versatile because you get both the key and the value in each iteration. You'll use it all the time.
Diagram: Dictionary Iteration Flowchart
Dictionary Iteration Flowchart MicroSim
Type: diagram
sim-id: dictionary-iteration
Library: p5.js
Status: Specified
Bloom Level: Understand (L2) Bloom Verb: trace, explain
Learning Objective: Students will be able to trace through different dictionary iteration patterns (keys, values, items) and predict the output at each step.
Purpose: An animated flowchart that visually steps through a for loop iterating over a dictionary, showing which key-value pair is being visited at each step and what the loop variable holds.
Layout:
- Top: A dictionary visualized as a table with keys and values
- Middle: A for-loop code block with the current iteration highlighted
- Bottom: The output console showing what has been printed so far
Interactive elements:
- Dropdown to select iteration type: "keys", "values", "items"
- "Step" button to advance one iteration at a time
- "Auto Play" button with speed control
- "Reset" button to restart
- The current key-value pair highlights in the dictionary table as the loop visits it
Color scheme: Current item highlighted in yellow, visited items in light gray, unvisited in white Responsive: Canvas adjusts to window width
Instructional Rationale: Stepping through iteration one element at a time with visual highlighting helps students build a mental model of how Python traverses dictionary contents. Comparing the three iteration modes side by side reveals when to use each one.
Dictionary Comprehension
Just like list comprehensions, dictionary comprehensions let you build a dictionary in a single, elegant line. The syntax looks similar, but you provide both a key expression and a value expression.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | |
Dictionary comprehensions are perfect for transforming data. Need to flip a dictionary's keys and values? One line:
1 2 3 4 | |
Nested Dictionaries
Nested dictionaries are dictionaries that contain other dictionaries as values. They're great for representing structured, multi-level data — like a class roster where each student has multiple attributes.
1 2 3 4 5 6 7 8 9 10 11 12 | |
Think of nested dictionaries like folders inside folders on your computer. The outer dictionary is the main folder, and each value is a subfolder containing more detailed information.
Diagram: Nested Dictionary Explorer
Nested Dictionary Explorer MicroSim
Type: microsim
sim-id: nested-dictionary
Library: p5.js
Status: Specified
Bloom Level: Apply (L3) Bloom Verb: navigate, construct
Learning Objective: Students will be able to navigate through nested dictionaries by clicking through levels of keys and constructing the bracket-chain notation needed to access deeply nested values.
Purpose: An interactive tree visualization of a nested dictionary where students can expand and collapse levels, and the tool generates the Python access expression for any selected value.
Layout:
- Left panel: A tree view of the nested dictionary, with expandable/collapsible nodes
- Right panel: The Python code showing the full access expression for the currently selected node
- Bottom: An input field where students can type an access expression and see the resulting value
Interactive elements:
- Click a key node to expand/collapse its children
- Click a leaf value to highlight it and display the full access path (e.g.,
classroom["Alice"]["gpa"]) - Type an access expression in the input field and press Enter to see if it returns the correct value
- "Add Entry" button to add a new key-value pair at any level
Visual style: Tree layout with indented levels, color-coded by depth Responsive: Panels stack vertically on narrow screens
Instructional Rationale: Interactive tree navigation lets students build intuition for how nested access works. Seeing the access expression update as they click through levels connects the visual structure to the Python syntax.
Dictionary Merging
Dictionary merging combines two or more dictionaries into one. Python 3.9 introduced the | operator for this, making it clean and readable.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | |
In all three cases, when both dictionaries have the same key, the right-hand dictionary's value wins. In the example above, user_prefs overrides defaults for "color" and "size", while "font" carries over from defaults since the user didn't set one.
Monty says: Here's a handy trick!
The | merge operator is my favorite way to combine dictionaries. It's clean, it's readable, and it doesn't modify either original dictionary. If you're using Python 3.9 or later (which you probably are), give it a try!
Practical Patterns with Dictionaries
Now that you know the fundamentals, let's look at some real-world patterns where dictionaries really shine. These patterns come up constantly in programming — from homework assignments to professional software.
Counting with Dicts
Counting with dicts is one of the most common dictionary patterns. The idea is simple: use keys to represent the items you're counting, and values to track how many times each item appears.
1 2 3 4 5 6 7 8 9 | |
Let's trace through how this works:
- We start with an empty dictionary
- For each letter,
get(letter, 0)returns the current count (or0if it's the first time) - We add
1and store the new count back
This pattern is so useful that Python has a built-in shortcut for it in the collections module called Counter, but understanding the manual approach teaches you a lot about how dictionaries work.
1 2 3 4 5 6 7 8 9 | |
Grouping with Dicts
Grouping with dicts organizes items into categories. Each key is a category, and each value is a list of items that belong to that category.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
Here's a cleaner version using setdefault():
1 2 3 4 5 6 | |
The setdefault() method checks if the key exists. If it does, it returns the existing value. If not, it sets the default value (an empty list here) and returns it. Either way, you can immediately call .append() on the result.
Diagram: Counting and Grouping Patterns
Counting and Grouping Patterns MicroSim
Type: microsim
sim-id: dict-patterns
Library: p5.js
Status: Specified
Bloom Level: Apply (L3) Bloom Verb: implement, demonstrate
Learning Objective: Students will be able to implement counting and grouping patterns by watching how a dictionary builds up step by step as data is processed.
Purpose: A step-by-step animated visualization that shows how a dictionary grows as items are counted or grouped, with the dictionary state updating after each iteration.
Layout:
- Top: A selector to toggle between "Counting Mode" and "Grouping Mode"
- Left panel: The input data (a word for counting, or a list of student-grade tuples for grouping)
- Center: The current item being processed, highlighted
- Right panel: The dictionary, updated in real-time after each step
Interactive elements:
- "Step" button to process one item at a time
- "Auto Play" button with speed slider
- "Reset" button
- Toggle between counting and grouping modes
- Custom input field to type your own word or data set
Visual style: Dictionary displayed as a growing table with animated row additions and value updates Responsive: Panels stack vertically on narrow screens
Instructional Rationale: Watching the dictionary build up one entry at a time demystifies the counting and grouping patterns. Students can predict what the next step will produce before clicking "Step," turning observation into active practice.
Dictionary as Cache
A dictionary as cache (also called memoization) stores the results of expensive calculations so you don't have to repeat them. It's like keeping a cheat sheet of answers you've already figured out.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | |
Without caching, computing fib_slow(50) would take an absurdly long time because it recalculates the same values millions of times. With a dictionary cache, each value is calculated only once and then remembered. The 50th Fibonacci number comes back instantly.
This pattern works because dictionary lookups are incredibly fast — almost instant, no matter how many items are in the dictionary. Speaking of which...
Hashable Keys
Why can strings and numbers be dictionary keys, but lists can't? The answer involves something called a hash.
Hashable keys are keys that Python can convert into a fixed-size integer called a hash code. Python uses this hash code to figure out where to store the key-value pair internally, making lookups blazingly fast. It's like assigning each book in a library a specific shelf number — instead of searching every shelf, you go directly to the right one.
For this to work, keys must be immutable (unchangeable). If a key could change after being stored, its hash code would change, and Python wouldn't be able to find it anymore. It'd be like moving a library book to a different shelf without updating the catalog.
Here's what's hashable and what's not:
| Type | Hashable? | Can Be a Key? | Why? |
|---|---|---|---|
str |
Yes | Yes | Strings are immutable |
int |
Yes | Yes | Integers are immutable |
float |
Yes | Yes | Floats are immutable |
tuple |
Yes* | Yes* | *Only if it contains only hashable items |
bool |
Yes | Yes | Booleans are immutable |
list |
No | No | Lists are mutable (can change) |
dict |
No | No | Dicts are mutable |
set |
No | No | Sets are mutable |
1 2 3 4 5 6 7 8 9 | |
Monty says: You've got this!
Here's an easy rule of thumb: if you can't change it, you can hash it. Strings, numbers, and tuples are locked in place once created, so they make great dictionary keys. Lists, dictionaries, and sets can be modified, so Python won't let you use them as keys.
Dict vs List Lookup
Now for one of the most powerful reasons to use dictionaries: dict vs list lookup performance. Dictionaries are dramatically faster than lists when you need to check if something exists.
With a list, Python has to check each item one by one from the beginning. If the list has a million items, that could mean up to a million comparisons. This is called linear search — the time grows proportionally with the size of the list.
With a dictionary, Python uses the hash code to jump directly to the right spot. It doesn't matter if the dictionary has 10 items or 10 million — the lookup takes roughly the same amount of time. This is called constant time or O(1) lookup.
Here's a comparison:
| Operation | List | Dictionary |
|---|---|---|
| Check if item exists | O(n) — slow for large data | O(1) — fast regardless of size |
| Look up by index/key | O(1) by index | O(1) by key |
| Insert at end | O(1) | O(1) |
| Search for a value | Scan every element | Instant by key |
| Best for | Ordered sequences | Key-value lookups |
1 2 3 4 5 6 7 | |
Diagram: Dict vs List Lookup Performance
Dict vs List Lookup Performance MicroSim
Type: microsim
sim-id: dict-vs-list
Library: p5.js
Status: Specified
Bloom Level: Analyze (L4) Bloom Verb: compare, differentiate
Learning Objective: Students will be able to compare the lookup performance of lists vs dictionaries and explain why dictionaries are faster for membership testing.
Purpose: An animated race visualization that searches for a value in both a list and a dictionary simultaneously, showing the dramatic speed difference as data sizes grow.
Layout:
- Top: Slider to set the collection size (100, 1000, 10000, 100000)
- Center: Two lanes labeled "List Search" and "Dict Search"
- The list lane shows an animated cursor scanning through elements one by one
- The dict lane shows the hash calculation and direct jump
- Bottom: Timer showing elapsed comparison steps for each
Interactive elements:
- Size slider to change the number of items (demonstrates how list search time grows while dict stays constant)
- "Race!" button to start the comparison
- "Search for:" input to choose which value to search for
- Results display showing the number of steps each method took
Visual style: Racing lanes with animated search cursors, bar chart of steps taken Responsive: Canvas width adjusts to window
Instructional Rationale: A race visualization makes the abstract concept of time complexity visceral and memorable. Adjusting the data size lets students see firsthand that dictionary lookup time stays flat while list lookup time grows, building intuition for Big-O analysis.
In real programs, this performance difference matters a lot. If you're checking whether a username exists in a system with millions of users, a dictionary (or set) gives you an instant answer. A list would make your users wait.
1 2 3 4 5 6 7 8 9 10 11 12 | |
Diagram: Dictionary Use Cases Infographic
Dictionary Use Cases Infographic
Type: infographic
sim-id: dict-use-cases
Library: p5.js
Status: Specified
Bloom Level: Understand (L2) Bloom Verb: classify, summarize
Learning Objective: Students will be able to identify common real-world scenarios where dictionaries are the appropriate data structure and explain why.
Purpose: An interactive infographic showing 6 real-world dictionary use cases (phone book, word counter, grade book, shopping cart, game inventory, translation dictionary) with hover-to-reveal Python code examples.
Layout:
- 6 cards arranged in a 3x2 grid, each showing an icon and title for a use case
- Hovering over a card expands it to show a brief description and a Python code snippet
Interactive elements:
- Hover/click to expand each card
- A "Which data structure?" quiz mode where students see a scenario and choose between list, dictionary, tuple, or set
Visual style: Card-based layout with icons, clean typography Responsive: Cards reflow to 2x3 or 1x6 on narrower screens
Instructional Rationale: Connecting dictionary concepts to familiar real-world scenarios (phone books, grade books, shopping carts) helps students transfer abstract knowledge to practical application. Quiz mode provides immediate self-assessment.
Putting It All Together
Let's combine several dictionary techniques into a practical example. Imagine you're building a simple grade tracker for a class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | |
This example uses grouping with setdefault, dictionary comprehensions, and iteration — all in one natural, readable program. That's the power of dictionaries!
Monty says: You've got this!
Amazing work, coder! You've just learned one of the most important and versatile tools in Python. Dictionaries are everywhere — in web development, data science, game programming, and beyond. Every time you need to connect one piece of data to another, think dictionary!
Key Takeaways
- Dictionaries store data as key-value pairs — like a real dictionary maps words to definitions.
- Create dictionaries with curly braces:
{"key": "value"}or thedict()constructor. - Access values with square brackets
d["key"]or the saferget()method with a default value. - Essential methods:
keys(),values(),items(),update(),pop(). - Dictionary iteration with
items()gives you both keys and values in each loop. - Dictionary comprehensions let you build dictionaries in a single line:
{k: v for k, v in data}. - Nested dictionaries store structured, multi-level data by putting dictionaries inside dictionaries.
- Merge dictionaries with the
|operator (Python 3.9+),**unpacking, orupdate(). - Counting and grouping are the two most common dictionary patterns in real-world code.
- Caching (memoization) uses a dictionary to store previously computed results for speed.
- Keys must be hashable (immutable): strings, numbers, and tuples work; lists and dicts don't.
- Dict lookup is O(1) (constant time) vs list lookup which is O(n) (linear time) — dictionaries are dramatically faster for searching.
Check Your Understanding: What happens if you try to use a list as a dictionary key?
Python raises a TypeError: unhashable type: 'list'. Lists are mutable (they can be changed), which means Python can't compute a reliable hash code for them. Only immutable types like strings, integers, floats, and tuples (containing only hashable elements) can be used as dictionary keys. If you need a list-like key, convert it to a tuple first: d[tuple(my_list)] = value.
Check Your Understanding: Write a dictionary comprehension that maps each number from 1 to 5 to its cube.
1 2 3 | |
n ** 3 calculates the cube (n times n times n). The range(1, 6) generates numbers 1 through 5. The result is a dictionary where each key is a number and each value is its cube.
Check Your Understanding: Why are dictionary lookups faster than list lookups?
Dictionaries use hash codes to jump directly to where a key is stored, giving them O(1) constant time lookups — the speed doesn't depend on how many items are in the dictionary. Lists, on the other hand, must scan through elements one by one (O(n) linear time), so the more items in the list, the longer it takes. For a dictionary with a million entries, lookup is still essentially instant. For a list with a million entries, you might need to check all million items in the worst case.