Chapter 18 — Front Matter
Chapter Introduction and Learning Objectives
Lists are the workhorse of Python data structures, but they are not the only tool. Python gives you four built-in collection types: lists, tuples, sets, and dictionaries. Each one has a different shape, different rules, and different strengths. A skilled Python programmer picks the right structure for the job rather than forcing every problem into a list.
This chapter introduces tuples, sets, and dictionaries, explains when and why each one is useful, and shows you how to work with them through reading, tracing, and writing code. By the time you finish, you will have four tools in your toolbox instead of one — and, more importantly, a clear sense of when to reach for each one.
Opening Question
Suppose you are storing a student's name, age, and major. A list works: ["Maya", 19, "Biology"]. But what tells you that index 0 is the name and not the major? What stops someone from accidentally changing a coordinate that was never supposed to change? What happens when you need to count how many times each word appears in a paragraph, or check whether a value is in a collection of ten thousand items, instantly? Lists alone struggle with these questions. This chapter introduces three more collection types — each one solving a problem that lists solve awkwardly or not at all.
10Sections
17Key Terms
4Collection Types
30Total Chapters
Learning Objectives
By the end of this chapter, you should be able to:
- 1Explain why Python provides multiple collection types instead of just one.
- 2Create, index, slice, and unpack tuples, and explain why tuples are immutable.
- 3Identify situations where a tuple is the better choice over a list.
- 4Create sets, add and remove items, and explain why sets have no guaranteed order.
- 5Use sets to find unique values and test membership efficiently.
- 6Apply set operations: union, intersection, difference, and symmetric difference.
- 7Create dictionaries and explain how key-value pairs differ from positional indexing.
- 8Read, add, update, and remove dictionary entries, including safe lookup with
.get().
- 9Iterate over dictionary keys, values, and key-value pairs using
.keys(), .values(), and .items().
- 10Apply the dictionary counting pattern to tally occurrences in a collection.
- 11Choose the most appropriate collection type — list, tuple, set, or dictionary — for a given problem.
Chapter 18 — Contents
Sections at a Glance
- 18.1Why Python Has Multiple Collection TypesLists, tuples, sets, and dictionaries compared; ordered versus unordered; mutable versus immutable; lookup by position versus lookup by key
- 18.2TuplesCreating tuples; indexing and slicing; immutability; length and iteration; tuple unpacking; functions that return multiple values
- 18.3When Tuples Are UsefulFixed records; coordinates and colors; tuples as dictionary keys; multiple return values; a rule of thumb for choosing tuples over lists
- 18.4SetsCreating sets; automatic duplicate removal; unordered storage; adding and removing items; membership testing; union, intersection, difference, symmetric difference
- 18.5Unique Values and MembershipFinding unique values in a list; removing duplicates; fast membership testing for large collections
- 18.6Dictionaries and Key-Value PairsCreating dictionaries; key-value pairs; why dictionaries beat lists for labeled data
- 18.7Reading, Adding, and Updating Dictionary EntriesReading with brackets and
.get(); adding and updating entries; removing with del and .pop(); membership testing and length
- 18.8Iterating Through DictionariesLooping over keys, values, and items; tuple unpacking inside
.items(); building a formatted report
- 18.9Counting with DictionariesThe counting pattern; simplifying with
.get(); finding the most common item; counting characters in a string
- 18.10Choosing Lists, Tuples, Sets, or DictionariesA practical decision guide; a quick-reference table; mixing collection types as a bridge to Chapter 19
Sections 18.1 – 18.3
Fixed Records: Why Tuples Exist and When to Use Them
Multiple Collection Types · Tuples · Immutability · Unpacking
Section 18.1
Why Python Has Multiple Collection Types
Imagine you are a carpenter. You own a hammer, a screwdriver, a saw, and a measuring tape. Each tool does something specific. You could technically use only a hammer for every job, but the result would be awkward and fragile. A good carpenter reaches for the right tool naturally.
Python collections work the same way.
In Chapter 17 you learned that a list is an ordered, mutable sequence. Ordered means the items have a position you can rely on. Mutable means you can change, add, and remove items after the list is created.
Lists are excellent for many tasks. But sometimes you need a collection that:
- Cannot be changed after it is created (a fixed record like coordinates or a color)
- Stores only unique values and ignores duplicates automatically
- Lets you look up information by a label rather than a number
Python gives you three other tools for those situations.
| Collection | Ordered? | Mutable? | Duplicates? | Lookup by |
list | Yes | Yes | Yes | Index number |
tuple | Yes | No | Yes | Index number |
set | No | Yes | No | Membership only |
dict | Yes (insertion order) | Yes | Keys: No | Key name |
Study Note
You will get much more out of this chapter if you keep asking: Why would I choose this instead of a list? Each section answers that question for its own type.
Section 18.2
Tuples
A tuple is an ordered sequence of values, just like a list. The critical difference is that a tuple is immutable: once you create it, you cannot change its contents.
Creating a tuple
You write a tuple with parentheses and commas.
point = (3, 7)
color = (255, 128, 0)
person = ("Maya", 19, "Biology")
empty_tuple = ()
single = (42,) # Note the trailing comma — required for a one-item tuple
You can also create a tuple without parentheses by simply writing values separated by commas. Python recognizes the commas and creates a tuple automatically.
coordinates = 10, 20
print(type(coordinates)) # <class 'tuple'>
Using parentheses is usually clearer, but both forms are valid.
Accessing tuple items
Tuples use the same index rules as lists. The first item is at index 0. Negative indexes count from the end. Slicing works the same way.
point = (3, 7)
print(point[0]) # 3
print(point[1]) # 7
print(point[-1]) # 7
rgb = (255, 128, 0)
print(rgb[0:2]) # (255, 128)
Tuples are immutable
If you try to change a tuple item, Python raises a TypeError.
point = (3, 7)
point[0] = 10 # TypeError: 'tuple' object does not support item assignment
Not a Bug — A Feature
This is not a bug. It is the feature. When you store something in a tuple, you are declaring: this data should not change.
Tuple length and iteration
len() and for loops work exactly as they do with lists.
person = ("Maya", 19, "Biology")
print(len(person)) # 3
for item in person:
print(item)
# Maya
# 19
# Biology
Tuple unpacking
One of the most useful tuple features is unpacking: assigning each item in a tuple to its own variable in a single statement.
point = (3, 7)
x, y = point
print(x) # 3
print(y) # 7
person = ("Maya", 19, "Biology")
name, age, major = person
print(name) # Maya
print(age) # 19
print(major) # Biology
The number of variables on the left must match the number of items in the tuple, or Python raises a ValueError.
a, b = (1, 2, 3) # ValueError: too many values to unpack
Unpacking makes code much more readable than writing person[0], person[1], and person[2] every time.
Functions that return multiple values
Tuples make it natural for a function to return more than one value. When a function returns a comma-separated group of values, Python automatically packs them into a tuple.
def min_and_max(numbers):
return min(numbers), max(numbers)
low, high = min_and_max([4, 1, 9, 2, 7])
print(low) # 1
print(high) # 9
You have already used this pattern without knowing it — many Python functions and methods return tuples behind the scenes.
Section 18.3
When Tuples Are Useful
Tuples are not just stripped-down lists. They communicate meaning. Here are the situations where tuples make more sense than lists.
Fixed records
Some data naturally belongs together and should not be rearranged or changed. A geographic coordinate, an RGB color, a date, a playing card — these are fixed records.
seattle = (47.6062, -122.3321) # latitude, longitude
red = (255, 0, 0) # R, G, B
birthday = (1998, 6, 14) # year, month, day
Using a tuple instead of a list signals to anyone reading the code: the structure of this data is fixed. Do not modify it.
Dictionary keys
Lists cannot be used as dictionary keys because they are mutable. Tuples can, because they are immutable.
distances = {
("Seattle", "Portland"): 174,
("Seattle", "Vancouver"): 142,
}
print(distances[("Seattle", "Portland")]) # 174
You will see this pattern more in Chapter 19 and Chapter 20.
Multiple return values
As shown above, functions that naturally compute two or more results can return a tuple instead of requiring two separate function calls.
Slight performance benefit
Tuples are slightly faster and use slightly less memory than lists of the same size. For small programs this barely matters. For very large data sets it can add up. But correctness and clarity should always come first — do not switch from a list to a tuple for speed alone if your data genuinely needs to be modified.
Rule of Thumb
Use a tuple when the collection represents a fixed record, a coordinate, a function result, or any group of values that should not change. Use a list when you need to add, remove, or reorder items.
Sections 18.4 – 18.5
Uniqueness and Speed: Sets and Membership
Sets · Deduplication · Set Operations · Fast Membership Testing
Section 18.4
Sets
A set is an unordered collection of unique values. Sets are useful when you care about membership — whether a value is present — rather than order or position.
Creating a set
You write a set with curly braces.
fruits = {"apple", "banana", "cherry"}
primes = {2, 3, 5, 7, 11}
empty_set = set() # You cannot use {} for an empty set — that creates an empty dict
Watch Out
Sets use curly braces, just like dictionary literals. Python tells them apart because sets contain values while dictionaries contain key-value pairs separated by colons. An empty set must be written as set() — writing {} creates an empty dictionary instead.
You can also create a set from any iterable using set().
letters = set("hello")
print(letters) # {'h', 'e', 'l', 'o'} — only one 'l'
Sets remove duplicates automatically
If you add a value that already exists in the set, Python ignores it. There is no error and no duplicate.
tags = {"python", "beginner", "python", "tutorial", "beginner"}
print(tags) # {'python', 'beginner', 'tutorial'}
This is one of the most useful things about sets. If you want to find all unique values in a list, convert it to a set.
scores = [85, 90, 85, 72, 90, 88, 72]
unique_scores = set(scores)
print(unique_scores) # {72, 85, 88, 90}
Sets are unordered
Sets do not have a guaranteed order. You cannot access a set item by index.
fruits = {"apple", "banana", "cherry"}
print(fruits[0]) # TypeError: 'set' object is not subscriptable
When you print a set, the items may appear in any order. This is expected behavior.
Adding and removing items
Sets are mutable: you can change them after creation, even though you cannot index into them.
fruits = {"apple", "banana", "cherry"}
fruits.add("mango")
print(fruits) # {'apple', 'banana', 'cherry', 'mango'}
fruits.remove("banana")
print(fruits) # {'apple', 'cherry', 'mango'}
remove() raises a KeyError if the item is not found. Use discard() if you want to remove an item without an error when it is absent.
fruits.discard("pineapple") # No error even though pineapple is not in the set
Membership testing
Checking whether a value is in a set uses the in operator, just like lists. But sets are much faster at membership testing than lists for large collections, because of how they are stored internally.
approved = {"alice", "bob", "carol"}
if "alice" in approved:
print("Access granted")
if "dave" not in approved:
print("Access denied")
Iterating over a set
You can use a for loop with a set. Just remember that the order is not guaranteed.
languages = {"Python", "Java", "C", "JavaScript"}
for lang in languages:
print(lang)
# Output order will vary each run
Set operations
Sets support the mathematical operations you may have seen in a math class.
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
print(a | b) # Union: {1, 2, 3, 4, 5, 6} — all items in either set
print(a & b) # Intersection: {3, 4} — items in both sets
print(a - b) # Difference: {1, 2} — items in a but not b
print(a ^ b) # Symmetric difference: {1, 2, 5, 6} — items in one but not both
These operations are powerful for comparing lists, finding overlap, or filtering duplicates.
Section 18.5
Unique Values and Membership
Two practical problems come up again and again in programming: finding unique values and checking membership. Sets handle both naturally.
Finding unique values
responses = ["yes", "no", "yes", "maybe", "no", "yes"]
unique_responses = set(responses)
print(unique_responses) # {'yes', 'no', 'maybe'}
print(len(unique_responses)) # 3
If you want to count how many distinct values a collection contains, convert it to a set and call len().
Removing duplicates from a list
If you need a list back after removing duplicates, convert to a set and then back to a list.
scores = [88, 72, 88, 95, 72, 100]
unique_scores = list(set(scores))
print(unique_scores) # [72, 88, 95, 100] — order not guaranteed
A Limitation Worth Knowing
If you need the unique items in their original order, this approach loses the order. For now, the simple set conversion is fine. Order-preserving uniqueness requires a different technique you will learn in later courses.
Fast membership testing
Membership testing with in on a set is fast even for very large collections. The same test on a list checks each item one by one from the beginning. For a collection with millions of items, the difference is enormous.
# For small programs, both work fine
valid_codes = {"A100", "B200", "C300", "D400"}
user_code = input("Enter your code: ")
if user_code in valid_codes:
print("Valid code.")
else:
print("Invalid code.")
Sections 18.6 – 18.9
Lookup by Name: Dictionaries and the Counting Pattern
Key-Value Pairs · Reading and Updating · Iteration · Counting
Section 18.6
Dictionaries and Key-Value Pairs
A dictionary maps keys to values. Instead of looking up items by their position number, you look them up by a meaningful label. Dictionaries are one of the most important and most frequently used data structures in Python.
You have already seen a preview of dictionaries in earlier chapters. Now you will learn them properly.
Creating a dictionary
You write a dictionary with curly braces, colons to separate keys from values, and commas between pairs.
student = {
"name": "Maya",
"age": 19,
"major": "Biology",
"gpa": 3.8
}
Each entry is a key-value pair. The key is "name" and its value is "Maya". The key is "age" and its value is 19.
Keys are usually strings, but they can be any immutable type — integers, floats, or tuples work too. Values can be anything: strings, numbers, lists, other dictionaries, or any Python object.
empty_dict = {}
scores = {"Alice": 92, "Bob": 78, "Carol": 85}
settings = {"volume": 7, "fullscreen": True, "language": "English"}
Why dictionaries are not lists
Compare these two ways to store the same information.
# As a list — you must remember that index 0 is name, 1 is age, 2 is major
student_list = ["Maya", 19, "Biology"]
print(student_list[0]) # Maya — but why 0?
# As a dictionary — the key tells you what the value means
student_dict = {"name": "Maya", "age": 19, "major": "Biology"}
print(student_dict["name"]) # Maya — clear and readable
Why This Matters
Dictionaries make code self-documenting. The key tells you exactly what the value represents.
Section 18.7
Reading, Adding, and Updating Dictionary Entries
Reading a value
Use square brackets with a key to retrieve its value.
student = {"name": "Maya", "age": 19, "major": "Biology"}
print(student["name"]) # Maya
print(student["age"]) # 19
If the key does not exist, Python raises a KeyError.
print(student["gpa"]) # KeyError: 'gpa'
Use the .get() method to retrieve a value safely. If the key is missing, .get() returns None (or a default you specify) instead of raising an error.
print(student.get("gpa")) # None
print(student.get("gpa", 0.0)) # 0.0 — the default you provided
print(student.get("name", "Unknown")) # Maya — key exists, returns value
Adding a new entry
Assign a value to a new key. If the key does not exist, Python creates it.
student = {"name": "Maya", "age": 19}
student["major"] = "Biology"
student["gpa"] = 3.8
print(student)
# {'name': 'Maya', 'age': 19, 'major': 'Biology', 'gpa': 3.8}
Updating an existing entry
Assigning to an existing key replaces its value.
student = {"name": "Maya", "age": 19, "gpa": 3.8}
student["gpa"] = 3.9
print(student["gpa"]) # 3.9
Removing an entry
del removes a key-value pair.
student = {"name": "Maya", "age": 19, "major": "Biology"}
del student["age"]
print(student) # {'name': 'Maya', 'major': 'Biology'}
pop() removes a key and returns its value.
removed_major = student.pop("major")
print(removed_major) # Biology
print(student) # {'name': 'Maya'}
Checking membership
Use in to check whether a key exists in a dictionary.
student = {"name": "Maya", "age": 19}
print("name" in student) # True
print("gpa" in student) # False
Watch Out
in tests keys, not values.
Dictionary length
len() returns the number of key-value pairs.
student = {"name": "Maya", "age": 19, "major": "Biology"}
print(len(student)) # 3
Section 18.8
Iterating Through Dictionaries
You can loop through a dictionary in three ways, depending on what you need.
Iterating over keys (default)
A for loop over a dictionary gives you the keys.
scores = {"Alice": 92, "Bob": 78, "Carol": 85}
for name in scores:
print(name)
# Alice
# Bob
# Carol
You can call .keys() explicitly if it makes the code clearer.
for name in scores.keys():
print(name)
Iterating over values
Use .values() to loop through the values only.
for score in scores.values():
print(score)
# 92
# 78
# 85
Iterating over key-value pairs
Use .items() to get both the key and the value in each iteration. This is the most common approach when you need both.
for name, score in scores.items():
print(name, "scored", score)
# Alice scored 92
# Bob scored 78
# Carol scored 85
.items() returns each pair as a tuple, and the loop unpacks it into name and score automatically. This is the same tuple unpacking from section 18.2.
A practical example: printing a report
inventory = {
"pencils": 48,
"notebooks": 12,
"folders": 30,
"pens": 24
}
print("--- Inventory Report ---")
for item, quantity in inventory.items():
print(f" {item}: {quantity}")
print("Total items:", sum(inventory.values()))
Output
--- Inventory Report ---
pencils: 48
notebooks: 12
folders: 30
pens: 24
Total items: 114
Section 18.9
Counting with Dictionaries
One of the most common and powerful uses of dictionaries is counting: tracking how many times each value appears in a collection. This pattern is worth learning thoroughly because it appears in text analysis, surveys, logs, scores, and data processing.
The counting pattern
Here is the core idea: use a dictionary where each key is a value you want to count, and the associated dictionary value is how many times that key has appeared so far.
votes = ["Alice", "Bob", "Alice", "Carol", "Bob", "Alice", "Bob"]
counts = {}
for name in votes:
if name in counts:
counts[name] = counts[name] + 1
else:
counts[name] = 1
print(counts)
# {'Alice': 3, 'Bob': 3, 'Carol': 1}
Walk through this carefully.
- Start with an empty dictionary.
- For each name in the votes list, check whether the name is already a key.
- If it is, add 1 to its count.
- If it is not, create a new entry starting at 1.
Simplifying with .get()
You can write the same pattern more compactly using .get() with a default value of 0.
counts = {}
for name in votes:
counts[name] = counts.get(name, 0) + 1
If name is already a key, .get() returns its current count and you add 1. If name is new, .get() returns the default 0 and you add 1 to start the count at 1.
Two Correct Versions
Both versions are correct. Choose the one you can read and explain most easily.
Finding the most common item
Once you have a count dictionary, you can search it the same way you search any dictionary.
votes = ["Alice", "Bob", "Alice", "Carol", "Bob", "Alice", "Bob"]
counts = {}
for name in votes:
counts[name] = counts.get(name, 0) + 1
# Find the winner (highest count)
winner = None
highest = 0
for name, count in counts.items():
if count > highest:
winner = name
highest = count
print(f"{winner} wins with {highest} votes.")
# Alice wins with 3 votes.
Counting characters in a string
The counting pattern works on any iterable, including strings.
text = "mississippi"
letter_counts = {}
for char in text:
letter_counts[char] = letter_counts.get(char, 0) + 1
print(letter_counts)
# {'m': 1, 'i': 4, 's': 4, 'p': 2}
You will use this pattern in text processing, word frequency analysis, survey results, and many other applications.
Section 18.10
Putting It Together: Choosing the Right Structure
Decision Guide · Quick Reference · Bridge to Nested Structures
Section 18.10
Choosing Lists, Tuples, Sets, or Dictionaries
You now have four collection types. Choosing well makes programs clearer and more correct. Here is a practical guide.
Use a list when
- Order matters and you will need to refer to items by position.
- You need to add, remove, or change items.
- You may have duplicate values and that is fine.
- You are building a sequence to process one item at a time.
student_names = ["Alice", "Bob", "Carol", "David"]
Use a tuple when
- The data is a fixed record that should not change.
- You want to return multiple values from a function.
- You need to use the collection as a dictionary key.
- Position has a fixed meaning (first item is always x, second is always y).
location = (47.6062, -122.3321)
card = ("Queen", "Hearts")
Use a set when
- You only care whether items are present, not their order or position.
- You want to remove duplicates automatically.
- You need fast membership testing.
- You want to compare two collections using union, intersection, or difference.
visited_pages = {"home", "about", "contact"}
unique_words = set(word_list)
Use a dictionary when
- Each value has a meaningful label or name.
- You need to look up values by key.
- You are building a record with named fields.
- You are counting, grouping, or building a lookup table.
student = {"name": "Alice", "grade": "A", "score": 94}
word_counts = {"the": 48, "a": 31, "python": 12}
Quick decision table
| Question | Answer → Collection |
| Do I need items in order, with possible duplicates? | List |
| Is this a fixed record that should never change? | Tuple |
| Do I only care about uniqueness and membership? | Set |
| Does each value have a meaningful name? | Dictionary |
| Am I returning two or more values from a function? | Tuple |
| Am I counting how often each value appears? | Dictionary |
| Am I removing duplicates from a list? | Set (then convert back) |
Mixing types
Dictionaries can hold lists as values. Lists can hold tuples. Tuples can hold sets. You will explore nested structures in Chapter 19. For now, practice working with one collection type at a time and build toward combinations.
Chapter 18 — Back Matter
Chapter Summary
Python provides four built-in collection types, and each one serves a different purpose.
A tuple is an ordered, immutable sequence. Use it for fixed records like coordinates, colors, playing cards, or multiple function return values. Tuples signal that the structure of the data should not change. Tuple unpacking lets you assign each element to its own variable cleanly.
A set is an unordered collection of unique values. Sets automatically ignore duplicates. They excel at membership testing, deduplication, and mathematical operations like union and intersection. Sets do not support indexing because they have no guaranteed order.
A dictionary maps keys to values. It is one of the most important and frequently used data structures in Python. You look up values by key rather than by position number, which makes code readable and self-documenting. Dictionaries support adding, updating, removing, and iterating over entries. The counting pattern — building a dictionary of frequencies — is one of the most common dictionary idioms.
Choosing the right collection type is part of program design. A good programmer does not reach for a list by habit every time. They ask: is this data ordered or unordered? Fixed or mutable? Unique or possibly repeated? Labeled or positional? The answers point clearly toward the right tool.
Key Terms
tuple
An ordered, immutable sequence of values written with parentheses.
immutable
A collection or value that cannot be changed after it is created.
tuple unpacking
Assigning each element of a tuple to its own variable in a single statement.
set
An unordered collection of unique values written with curly braces.
union
A set operation that combines all items from two sets, removing duplicates.
intersection
A set operation that returns only items present in both sets.
difference
A set operation that returns items in the first set but not the second.
dictionary
A mutable collection of key-value pairs that allows lookup by key.
key
The label used to store and retrieve a value in a dictionary.
value (dictionary)
The data associated with a key in a dictionary.
key-value pair
A single entry in a dictionary, consisting of a key and its associated value.
.get()
A dictionary method that retrieves a value by key and returns a default instead of raising a KeyError when the key is missing.
.items()
A dictionary method that returns each key-value pair as a tuple, usable in a for loop.
.values()
A dictionary method that returns all values in a dictionary.
.keys()
A dictionary method that returns all keys in a dictionary.
counting pattern
A dictionary idiom that counts how many times each distinct value appears in a collection.
KeyError
The error raised when you try to access a dictionary key that does not exist.
membership testing
Checking whether a value is present in a collection using in.
Read each code block carefully. Describe what each line does and what the final output will be. Do not run the code until you have written your prediction.
Exercise 1
point = (4, -2)
x, y = point
print(f"x is {x}, y is {y}")
print(len(point))
Exercise 2
items = ["apple", "banana", "apple", "cherry", "banana", "apple"]
unique = set(items)
print(len(unique))
print("apple" in unique)
print("mango" in unique)
Exercise 3
scores = {"Alice": 88, "Bob": 74, "Carol": 91}
scores["David"] = 80
scores["Alice"] = 90
print(scores["Alice"])
print(len(scores))
Exercise 4
text = "banana"
counts = {}
for char in text:
counts[char] = counts.get(char, 0) + 1
print(counts)
Exercise 5
info = ("Jordan", "Chemistry", 3.7)
name, major, gpa = info
if gpa >= 3.5:
print(f"{name} is on the dean's list.")
else:
print(f"{name} is not on the dean's list.")
For each program, copy the tracing table and fill in variable values as execution proceeds.
Tracing Exercise 1
words = ["the", "cat", "sat", "on", "the", "mat", "the"]
counts = {}
for word in words:
counts[word] = counts.get(word, 0) + 1
print(counts)
| Step | word | counts (after this step) |
| 1 | "the" | |
| 2 | "cat" | |
| 3 | "sat" | |
| 4 | "on" | |
| 5 | "the" | |
| 6 | "mat" | |
| 7 | "the" | |
Tracing Exercise 2
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
c = a & b
d = a | b
e = a - b
print(len(c), len(d), len(e))
Trace the values of c, d, and e before predicting the output.
Write the exact output each program produces, or write ERROR and name the error type.
1.
colors = ("red", "green", "blue")
print(colors[1])
colors[1] = "yellow"
2.
animals = {"cat", "dog", "fish", "cat", "dog"}
print(len(animals))
3.
d = {"a": 1, "b": 2, "c": 3}
print(d.get("d", 0))
print(d.get("b", 0))
4.
nums = (10, 20, 30)
a, b = nums
print(a + b)
5.
inventory = {"pens": 10, "pencils": 25, "rulers": 5}
total = 0
for qty in inventory.values():
total += qty
print(total)
6.
roster = {"Alice", "Bob", "Carol"}
roster.add("David")
roster.add("Alice")
print(len(roster))
Each program below has one or more errors. Identify the error type, explain what is wrong, and write a corrected version.
Bug 1
record = ("Emma", 21, "Physics")
record[2] = "Chemistry"
print(record)
What kind of error is this? Why does it happen? How would you fix the data structure choice?
Bug 2
capitals = {"France": "Paris", "Germany": "Berlin", "Italy": "Rome"}
print(capitals["Spain"])
What error will this raise? Write two different fixes.
Bug 3
favorites = {}
for color in ["red", "blue", "red", "green", "blue", "red"]:
favorites[color] + 1
print(favorites)
This program runs without a crash on the first iteration. Trace what actually happens and explain why it does not count correctly. Write the corrected version.
Bug 4
tags = {}
tags.add("python")
tags.add("beginner")
print(tags)
Identify the error. What collection type should be used?
Bug 5
student = {"name": "Luis", "grade": "B"}
name, grade = student
print(name)
print(grade)
This looks like tuple unpacking, but it does not work as expected. What does iterating over a dictionary actually produce? Rewrite this using the correct approach.
- Task 1. Write a function called
make_record(name, age, city) that returns a tuple containing those three values. Then write code that calls the function, unpacks the result, and prints a sentence like "Alice, age 22, lives in Chicago."
- Task 2. Write a program that asks the user to enter five words, stores them in a list, converts the list to a set, and prints how many unique words were entered.
- Task 3. Write a function called
word_count(sentence) that takes a string, splits it into words, counts each word using a dictionary, and returns the count dictionary. Test it with at least two sentences.
- Task 4. Given this dictionary:
prices = {"apple": 0.99, "banana": 0.59, "cherry": 3.49, "mango": 1.79}
Write a loop that prints only the items that cost more than $1.00, formatted like:
cherry: $3.49
mango: $1.79
- Task 5. Write a function called
most_frequent(items) that takes a list and returns the item that appears most often. Use a dictionary to count occurrences. If there is a tie, returning any one of the tied items is acceptable.
- Task 6. Write a program that stores the following data using the most appropriate collection type and explain your choice in a comment.
- The three primary colors: red, yellow, blue
- A student's name, student ID number, and enrollment year
- The population of five cities, looked up by city name
- All unique letters that appear in the word
"programming"
- Task 7. Write a function called
shared_items(list_a, list_b) that takes two lists and returns a sorted list of items that appear in both. Use sets to find the intersection.
Build a simple contact book program that stores contacts as a dictionary and supports adding, looking up, listing, and removing contacts.
Requirements
- Each contact should be stored as a dictionary inside a larger dictionary. The outer dictionary uses the contact's name as the key. The value is a dictionary with at least
"phone" and "email" fields.
- The program should offer a menu with these options: add a contact, look up a contact by name, list all contacts, remove a contact, and quit.
- When looking up a contact, the program should handle the case where the name is not found — no crash, just a friendly message.
- When listing all contacts, print each name followed by their phone number and email.
Example structure
Starter skeleton
def add_contact(contacts, name, phone, email):
# Add a new contact
pass
def lookup_contact(contacts, name):
# Return the contact's info or a message if not found
pass
def list_contacts(contacts):
# Print all contacts
pass
def remove_contact(contacts, name):
# Remove a contact if they exist
pass
def main():
contacts = {}
# Menu loop goes here
pass
main()
Extension challenges
- Add a
"notes" field to each contact.
- Allow searching by phone number as well as by name.
- Count and display how many contacts are stored.
- Detect and reject duplicate names when adding.
These questions use material from Chapters 1–18. Work through them without looking up answers first.
- 1. Without running the code, predict the output.
data = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3]
unique = set(data)
print(sorted(unique))
- 2. A student writes this function:
def swap(pair):
a, b = pair
return b, a
result = swap((10, 20))
print(result)
What does this print? What data type is result?
- 3. Explain the difference between these two lines:
student["gpa"] = 4.0 # Line A
student.get("gpa", 0.0) # Line B
- 4. You have a list of 10,000 usernames and need to check thousands of times whether a specific username is in the list. Should you use a list or a set? Explain your reasoning.
- 5. Write a function called
invert(d) that takes a dictionary and returns a new dictionary with keys and values swapped. Assume all values in the original dictionary are unique.
# Example
original = {"a": 1, "b": 2, "c": 3}
print(invert(original)) # {1: 'a', 2: 'b', 3: 'c'}
- 6. What will this print? Explain why.
a = {1, 2, 3}
b = {2, 3, 4}
print(a - b)
print(b - a)
Chapter 18 Checklist
Use this to confirm your understanding before moving to Chapter 19
Concepts
- I can explain why Python provides multiple collection types instead of just one.
- I can create, index, slice, and unpack tuples.
- I can explain why tuples are immutable and why that matters.
- I can create sets, add and remove items, and explain why sets have no guaranteed order.
- I can apply set operations: union, intersection, difference, and symmetric difference.
- I can create dictionaries and explain key-value pairs.
- I can read, add, update, and remove dictionary entries safely.
- I can iterate over keys, values, and items in a dictionary.
- I can apply the counting pattern to tally occurrences in a collection.
Applications
- I can choose the most appropriate collection type for a given problem.
- I can use a tuple to return multiple values from a function.
- I can use a set to find unique values and test membership efficiently.
- I can build a simple program around a dictionary, such as a contact book.
Study Habits
- I trace dictionary and set changes step by step rather than guessing the final result.
- I can explain, in my own words, why a tuple is not just "a list that cannot change."
- I ask myself "ordered or unordered? fixed or mutable? unique or repeated? labeled or positional?" before choosing a collection.
Preview — Chapter 19
Nested Data Structures
Chapter 18 showed you how to work with one collection at a time. Real programs often need collections inside collections: a list of dictionaries, a dictionary whose values are lists, a list of tuples, a table made from a list of lists. Chapter 19 — Nested Data Structures — teaches you how to build, read, trace, and navigate data that has this kind of depth. You will model real-world records like gradebooks, inventories, class rosters, and simple databases. You will write nested loops to process them and learn how to design your data shape before you write a single line of code. The skills from Chapter 18 are essential preparation. Make sure you can create, read, update, and iterate over lists, tuples, sets, and dictionaries comfortably before moving on.
MGU Library Connection
- Programming with Python — Appendix H: Data Structure Reference
- Programming with Python — Appendix C: Python Syntax Quick Reference
- Companion resource: Dictionary Methods Chart
- Companion resource: List Methods Chart
- Companion resource: Data Structure Selection Guide
- Next chapter: Nested Data Structures (Chapter 19) — requires comfort with tuples, sets, and dictionaries