Skip to content

Lists

Summary

This chapter introduces Python lists, the most versatile built-in data structure. Students will learn to create, index, slice, and modify lists. The chapter covers essential list methods (append, insert, remove, pop, sort, reverse), list comprehensions for concise creation, nested lists, and traversal patterns. Lists are fundamental to nearly every non-trivial Python program.

Concepts Covered

This chapter covers the following 20 concepts from the learning graph:

  1. Lists
  2. List Creation
  3. List Indexing
  4. List Slicing
  5. List Mutability
  6. List Methods
  7. Append Method
  8. Insert Method
  9. Remove Method
  10. Pop Method
  11. Sort Method
  12. Reverse Method
  13. List Comprehension
  14. Nested Lists
  15. List of Lists
  16. List Traversal
  17. For Loop with Lists
  18. Enumerate Function
  19. List Unpacking
  20. Zip Function

Prerequisites

This chapter builds on concepts from:


Monty says: Let's code this!

Monty Welcome back, coders! So far you've worked with single values — a number here, a string there. But what if you need to keep track of dozens of values? A playlist of songs, a roster of students, a shopping list? That's where Python lists come in, and they're about to become your new best friend. Let's dive in!

What Are Lists?

Imagine you're packing for a trip, and you write down everything you need: "phone, charger, snacks, headphones, sunscreen." That written packing list is a collection of items grouped together under one name — your packing list. Python lists work the same way.

A list is an ordered collection of items stored in a single variable. Instead of creating five separate variables for five items, you put them all in one list. Lists are like the Swiss Army knife of Python — they're flexible, powerful, and you'll use them constantly.

Here's a taste of what a list looks like in Python:

1
2
packing_list = ["phone", "charger", "snacks", "headphones", "sunscreen"]
print(packing_list)
1
['phone', 'charger', 'snacks', 'headphones', 'sunscreen']

That's it! Square brackets, items separated by commas, and you've got yourself a list.

Creating Lists

List creation in Python is straightforward. You use square brackets [] and separate each item with a comma. Here are several ways to create lists:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# A list of strings
fruits = ["apple", "banana", "cherry"]

# A list of numbers
scores = [95, 87, 92, 78, 100]

# A list of mixed types (yes, Python allows this!)
mixed = ["Alice", 16, True, 3.14]

# An empty list (ready to be filled later)
empty = []

# Using the list() constructor
letters = list("hello")  # Creates ['h', 'e', 'l', 'l', 'o']

A few things to notice:

  • Lists can hold any type of data — strings, integers, floats, booleans, and even other lists
  • You can mix different types in the same list (though it's usually cleaner to keep them consistent)
  • An empty list [] is totally valid — think of it as an empty shopping bag waiting to be filled

You can also find out how many items are in a list using the built-in len() function:

1
2
fruits = ["apple", "banana", "cherry"]
print(len(fruits))  # Output: 3

Diagram: List Creation Visualizer

List Creation Visualizer

Type: microsim sim-id: list-creation-visualizer
Library: p5.js
Status: Specified

Bloom Level: Understand (L2) Bloom Verb: interpret, illustrate

Learning Objective: Students will be able to create Python lists and visualize how items are stored in indexed positions.

Purpose: An interactive visualization showing how Python stores list elements in sequential memory positions. Students type items into a text field and see them appear as labeled boxes in a visual list representation.

Canvas layout: - Top section: Title "List Creation Visualizer" - Text input field where students can type comma-separated values - A "Create List" button that renders the list - Visual representation: horizontal row of colored boxes, each containing an item - Above each box: the index number (0, 1, 2, ...) - Below the boxes: the Python code representation (e.g., ["apple", "banana", "cherry"]) - Preset buttons: "Fruits", "Numbers", "Mixed Types", "Empty" to load example lists

Interactive elements: - Type comma-separated values and press "Create List" to see the visual - Click preset buttons to load example data - Hover over any box to highlight the index and the value - A "Add Item" button to append one more item to the existing list, animating it sliding into position

Visual style: Clean colored boxes with rounded corners, index labels in a contrasting color above Color scheme: Alternating soft blue and green boxes; index labels in dark gray Responsive: Boxes resize based on number of items and window width

Instructional Rationale: Visualization of sequential indexed storage helps students build a mental model of how list data is organized internally. The ability to create custom lists encourages experimentation, while preset examples scaffold the experience.

Accessing List Items: Indexing

Okay, so you've created a list. How do you get a specific item out of it? That's where list indexing comes in.

Every item in a list has a position number called an index. And here's the part that trips up almost everyone at first: Python starts counting at 0, not 1. The first item is at index 0, the second at index 1, and so on.

1
2
3
4
5
6
fruits = ["apple", "banana", "cherry", "date", "elderberry"]
#          index 0   index 1   index 2   index 3   index 4

print(fruits[0])   # apple
print(fruits[2])   # cherry
print(fruits[4])   # elderberry

Why does Python start at 0? It's a computer science tradition that goes back to how memory addresses work. Don't fight it — embrace it. Soon it'll feel completely natural.

Python also supports negative indexing, which counts from the end of the list. The last item is index -1, the second-to-last is -2, and so on:

1
2
3
print(fruits[-1])   # elderberry (last item)
print(fruits[-2])   # date (second to last)
print(fruits[-3])   # cherry

Here's a handy reference table:

Item Positive Index Negative Index
"apple" 0 -5
"banana" 1 -4
"cherry" 2 -3
"date" 3 -2
"elderberry" 4 -1

Monty says: You've got this!

Monty Think of negative indices as a shortcut. Instead of calculating len(my_list) - 1 to find the last item, just use my_list[-1]. It's Python's way of being thoughtful — because who wants to do extra math when you don't have to?

If you try to access an index that doesn't exist, Python raises an IndexError:

1
2
fruits = ["apple", "banana", "cherry"]
print(fruits[10])  # IndexError: list index out of range

So always make sure your index is within the valid range.

Slicing: Getting Multiple Items

What if you want more than one item? List slicing lets you grab a portion of a list using the syntax list[start:stop]. This returns a new list containing items from index start up to (but not including) index stop.

1
2
3
4
5
6
7
fruits = ["apple", "banana", "cherry", "date", "elderberry"]

print(fruits[1:4])   # ['banana', 'cherry', 'date']
print(fruits[0:3])   # ['apple', 'banana', 'cherry']
print(fruits[2:])    # ['cherry', 'date', 'elderberry']  (from index 2 to the end)
print(fruits[:3])    # ['apple', 'banana', 'cherry']  (from the start to index 3)
print(fruits[:])     # A copy of the entire list

You can also add a step value with list[start:stop:step]:

1
2
3
4
5
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

print(numbers[0:10:2])   # [0, 2, 4, 6, 8]  (every other item)
print(numbers[::3])      # [0, 3, 6, 9]  (every third item)
print(numbers[::-1])     # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]  (reversed!)

Here's a quick reference for slicing syntax:

Syntax Meaning
list[a:b] Items from index a to b-1
list[a:] Items from index a to the end
list[:b] Items from the start to b-1
list[:] A copy of the entire list
list[a:b:c] Every cth item from a to b-1
list[::-1] The list in reverse

Diagram: List Indexing and Slicing Explorer

List Indexing and Slicing Explorer

Type: microsim sim-id: list-index-slice-explorer
Library: p5.js
Status: Specified

Bloom Level: Apply (L3) Bloom Verb: demonstrate, use

Learning Objective: Students will be able to use positive and negative indices to access specific list items and apply slice notation to extract sublists.

Purpose: An interactive tool where students type index or slice expressions and immediately see which items are selected from a visual list.

Canvas layout: - Top section: Title "List Indexing & Slicing Explorer" - A visual horizontal row of 8 colored boxes representing a list: ["ant", "bee", "cat", "dog", "elk", "fox", "goat", "hawk"] - Above each box: positive index (0-7) - Below each box: negative index (-8 to -1) - An input field labeled "Enter expression:" where students type things like [2], [1:5], [-3:], [::2] - A result display showing the Python output - The selected boxes highlight (glow/enlarge) in the visual

Interactive elements: - Type any valid index or slice expression and press Enter - Selected items glow bright yellow in the visual row - Preset example buttons: [0], [-1], [2:5], [:3], [::2], [::-1] - An "Explain" toggle that shows a step-by-step breakdown of how the slice was computed

Visual style: Horizontal boxes with item labels inside, index labels above and below in smaller text Color scheme: Default box color is soft blue; selected items highlight in bright gold; error states show red border Responsive: Box sizes adjust for window width

Instructional Rationale: Direct manipulation lets students test their understanding of index/slice syntax with immediate visual feedback. The "Explain" mode scaffolds learning by showing the computational steps behind each expression. Negative indices and step values are notoriously confusing, and this hands-on approach builds fluency faster than reading alone.

List Mutability: Lists Can Change

Here's something that makes lists special compared to strings: list mutability. A mutable object is one you can change after creating it. Lists are mutable, which means you can add items, remove items, or swap out individual elements whenever you want.

1
2
3
colors = ["red", "green", "blue"]
colors[1] = "yellow"       # Replace "green" with "yellow"
print(colors)              # ['red', 'yellow', 'blue']

Compare this to strings, which are immutable (you can't change them in place):

1
2
name = "hello"
name[0] = "H"    # TypeError! Strings can't be modified

This mutability is one of the reasons lists are so popular. Think of a list like a whiteboard — you can erase and rewrite as much as you want. A string is more like a printed poster — once it's made, you need a whole new poster to change it.

You can also replace a range of items using slicing:

1
2
3
numbers = [1, 2, 3, 4, 5]
numbers[1:4] = [20, 30, 40]
print(numbers)  # [1, 20, 30, 40, 5]

List Methods: Your Toolkit

Now let's get to the really good stuff. Python lists come with a bunch of built-in list methods — special functions attached to lists that let you add, remove, sort, and manipulate items. Think of them as tools in a toolbox, each designed for a specific job.

Here's a reference table of the most important list methods:

Method What It Does Example Result
append(x) Adds x to the end [1, 2].append(3) [1, 2, 3]
insert(i, x) Inserts x at index i [1, 3].insert(1, 2) [1, 2, 3]
remove(x) Removes the first occurrence of x [1, 2, 3, 2].remove(2) [1, 3, 2]
pop(i) Removes and returns item at index i [1, 2, 3].pop(1) Returns 2; list becomes [1, 3]
sort() Sorts the list in ascending order [3, 1, 2].sort() [1, 2, 3]
reverse() Reverses the list in place [1, 2, 3].reverse() [3, 2, 1]
index(x) Returns the index of first occurrence of x [10, 20, 30].index(20) 1
count(x) Counts how many times x appears [1, 2, 2, 3].count(2) 2
clear() Removes all items [1, 2, 3].clear() []
copy() Returns a shallow copy [1, 2, 3].copy() [1, 2, 3] (new list)
extend(L) Adds all items from list L [1, 2].extend([3, 4]) [1, 2, 3, 4]

Let's look at the most important ones in detail.

The Append Method

The append method adds a single item to the end of a list. It's like getting in the back of a line — new items always go last.

1
2
3
4
5
6
playlist = ["Song A", "Song B"]
playlist.append("Song C")
print(playlist)  # ['Song A', 'Song B', 'Song C']

playlist.append("Song D")
print(playlist)  # ['Song A', 'Song B', 'Song C', 'Song D']

append() is probably the list method you'll use most often. Building a list piece by piece? Start empty and keep appending:

1
2
3
4
squares = []
for i in range(1, 6):
    squares.append(i ** 2)
print(squares)  # [1, 4, 9, 16, 25]

The Insert Method

The insert method lets you add an item at a specific position. It takes two arguments: the index where you want the item to go, and the item itself.

1
2
3
guests = ["Alice", "Charlie", "Diana"]
guests.insert(1, "Bob")      # Insert "Bob" at index 1
print(guests)  # ['Alice', 'Bob', 'Charlie', 'Diana']

Everything after the insertion point shifts one position to the right to make room. Think of it like cutting in line at a movie theater — everyone behind you has to take a step back.

The Remove Method

The remove method removes the first occurrence of a specified value from the list:

1
2
3
colors = ["red", "blue", "green", "blue", "yellow"]
colors.remove("blue")
print(colors)  # ['red', 'green', 'blue', 'yellow']

Notice that only the first "blue" was removed. The second "blue" is still there. If the value isn't found, Python raises a ValueError:

1
colors.remove("purple")  # ValueError: list.remove(x): x not in list

Monty says: Watch out!

Monty Be careful with remove() — it only removes the first match, not all of them! If you need to remove every occurrence of a value, you'll need a loop or a list comprehension. Also, calling remove() on a value that isn't in the list will crash your program. Always check first with if value in my_list: before removing.

The Pop Method

The pop method removes an item at a given index and returns it. This is handy when you want to use the removed value:

1
2
3
4
tasks = ["homework", "dishes", "laundry", "coding"]
done = tasks.pop(0)        # Remove and return the first item
print(done)                # homework
print(tasks)               # ['dishes', 'laundry', 'coding']

If you call pop() with no argument, it removes and returns the last item:

1
2
3
last_task = tasks.pop()
print(last_task)           # coding
print(tasks)               # ['dishes', 'laundry']

Think of pop() like a stack of cafeteria trays — you always take the top one off (the last item added).

The Sort Method

The sort method arranges items in ascending order (smallest to largest, A to Z):

1
2
3
4
5
6
7
scores = [85, 92, 78, 95, 88]
scores.sort()
print(scores)  # [78, 85, 88, 92, 95]

names = ["Charlie", "Alice", "Bob"]
names.sort()
print(names)  # ['Alice', 'Bob', 'Charlie']

To sort in descending order, pass reverse=True:

1
2
scores.sort(reverse=True)
print(scores)  # [95, 92, 88, 85, 78]

Important: sort() modifies the list in place and returns None. If you want a sorted copy without changing the original, use the built-in sorted() function instead:

1
2
3
4
original = [3, 1, 4, 1, 5]
new_list = sorted(original)
print(original)    # [3, 1, 4, 1, 5]  (unchanged!)
print(new_list)    # [1, 1, 3, 4, 5]

The Reverse Method

The reverse method flips the list around so the last item becomes the first and vice versa:

1
2
3
countdown = [1, 2, 3, 4, 5]
countdown.reverse()
print(countdown)  # [5, 4, 3, 2, 1]

Like sort(), reverse() modifies the list in place and returns None.

Diagram: List Methods Playground

List Methods Playground

Type: microsim sim-id: list-methods-playground
Library: p5.js
Status: Specified

Bloom Level: Apply (L3) Bloom Verb: apply, demonstrate, experiment

Learning Objective: Students will be able to apply common list methods (append, insert, remove, pop, sort, reverse) and predict the resulting list state.

Purpose: An interactive sandbox where students can apply list methods to a visual list and see the result animated step by step.

Canvas layout: - Top section: Title "List Methods Playground" - A visual horizontal row of colored boxes representing the current list state - Index labels above each box - Method buttons arranged below the list: "append", "insert", "remove", "pop", "sort", "reverse" - An input field for the value argument (used by append, insert, remove) - An input field for the index argument (used by insert, pop) - A "History" panel on the right showing previous operations and their results - A "Reset" button to restore the list to its initial state

Default list: [64, 25, 12, 78, 36]

Interactive elements: - Click a method button to apply it to the current list - append: prompts for value, new box slides in from the right with animation - insert: prompts for index and value, box squeezes in at the position and others shift right - remove: prompts for value, the matching box flashes red and disappears, others shift left - pop: prompts for index (optional), the box flies upward and a "returned value" label appears - sort: boxes shuffle/slide to their sorted positions with smooth animation - reverse: boxes flip positions with a mirrored animation - History panel logs each operation as Python code (e.g., list.append(42))

Visual style: Rounded rectangle boxes with numbers inside, smooth CSS-style transitions for additions/removals Color scheme: Boxes in various pastel colors, active operation highlighted in gold Responsive: Adjusts box sizes and layout for different screen widths

Instructional Rationale: A sandbox environment supports the Apply level by letting students freely experiment with each method and observe the state change. Animated transitions make the "shift" behavior of insert/remove visible, which is a common source of confusion. The history panel provides a record for self-review.

List Comprehensions

Ready for one of Python's coolest features? List comprehension is a concise way to create a new list by transforming or filtering items from an existing sequence. It packs a for loop (and optionally an if condition) into a single line.

Let's start with a regular loop and then see the comprehension version:

1
2
3
4
5
6
7
8
9
# Regular loop approach
squares = []
for x in range(1, 6):
    squares.append(x ** 2)
print(squares)  # [1, 4, 9, 16, 25]

# List comprehension (same result, one line!)
squares = [x ** 2 for x in range(1, 6)]
print(squares)  # [1, 4, 9, 16, 25]

The general syntax is:

1
new_list = [expression for item in iterable]

Read it like a sentence: "Give me expression for each item in iterable."

You can also add a filter with an if clause:

1
2
3
4
5
6
7
8
# Only even numbers
evens = [x for x in range(1, 11) if x % 2 == 0]
print(evens)  # [2, 4, 6, 8, 10]

# Uppercase only the long words
words = ["hi", "hello", "hey", "greetings"]
long_words = [w.upper() for w in words if len(w) > 3]
print(long_words)  # ['HELLO', 'GREETINGS']

Here are some more handy examples:

Task List Comprehension
Squares of 1-10 [x**2 for x in range(1, 11)]
Even numbers from a list [x for x in nums if x % 2 == 0]
First letters of words [w[0] for w in words]
Convert strings to ints [int(s) for s in string_list]
Lengths of words [len(w) for w in words]

Monty says: Let's debug this together!

Monty List comprehensions are powerful, but don't try to cram too much logic into one line. If your comprehension is getting long and hard to read, it's totally fine to use a regular for loop instead. Code clarity beats cleverness every time. Your future self (reading the code six months from now) will thank you!

Nested Lists and Lists of Lists

A list can contain anything — including other lists! When you put a list inside a list, you get a nested list. A collection of lists stored inside an outer list is sometimes called a list of lists.

This is super useful for representing grids, tables, and matrix-like data:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# A 3x3 tic-tac-toe board
board = [
    ["X", "O", "X"],
    ["O", "X", "O"],
    ["O", "X", "X"]
]

# Access a specific cell: row first, then column
print(board[0][2])   # X  (row 0, column 2)
print(board[1][1])   # X  (row 1, column 1)
print(board[2][0])   # O  (row 2, column 0)

The first index picks the row (the inner list), and the second index picks the item within that row. Think of it like a spreadsheet: board[row][column].

Here's another example — a gradebook:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# Each inner list: [student_name, exam1, exam2, exam3]
grades = [
    ["Alice", 92, 88, 95],
    ["Bob", 85, 90, 87],
    ["Charlie", 78, 82, 80]
]

# Get Bob's second exam score
print(grades[1][2])  # 90

# Get all of Alice's scores
print(grades[0][1:])  # [92, 88, 95]

You can visualize nested lists like a table:

Index [0] Name [1] Exam 1 [2] Exam 2 [3] Exam 3
grades[0] "Alice" 92 88 95
grades[1] "Bob" 85 90 87
grades[2] "Charlie" 78 82 80

Diagram: Nested List Grid Visualizer

Nested List Grid Visualizer

Type: microsim sim-id: nested-list-grid
Library: p5.js
Status: Specified

Bloom Level: Understand (L2) Bloom Verb: interpret, explain

Learning Objective: Students will be able to access elements in nested lists using double-index notation and interpret a list of lists as a 2D grid.

Purpose: An interactive grid that visualizes a nested list (list of lists) and lets students click on cells to see the double-index expression needed to access each element.

Canvas layout: - Top section: Title "Nested List Grid Visualizer" - A visual grid of cells representing a 4x4 nested list - Row indices (0-3) labeled on the left - Column indices (0-3) labeled on top - An expression display below the grid showing grid[row][col] = value - A Python code panel showing the full nested list definition - Preset grids: "Tic-Tac-Toe", "Number Grid", "Gradebook"

Default grid:

1
2
3
4
5
6
grid = [
    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 10, 11, 12],
    [13, 14, 15, 16]
]

Interactive elements: - Click any cell to highlight it and display grid[row][col] = value below - Clicking a row label highlights the entire row and shows grid[row] - A "Quiz Mode" button: displays a target expression like grid[2][1] and asks the student to click the correct cell - Preset buttons swap in different grid examples

Visual style: Clean grid with labeled axes, selected cells glow gold, row highlight in soft blue Color scheme: Grid cells in alternating light gray and white, indices in dark blue Responsive: Grid cell sizes adjust to window width

Instructional Rationale: Clicking individual cells and seeing the double-index expression reinforces the row-then-column access pattern. Quiz Mode provides retrieval practice. Multiple preset grids show that nested lists can represent diverse data types (numbers, strings, mixed).

List Traversal: Walking Through a List

One of the most common things you'll do with lists is go through each item one at a time. This is called list traversal — visiting every element in order. Python's for loop makes this incredibly easy.

For Loop with Lists

The most basic way to traverse a list is with a for loop:

1
2
3
4
fruits = ["apple", "banana", "cherry", "date"]

for fruit in fruits:
    print(f"I like {fruit}!")
1
2
3
4
I like apple!
I like banana!
I like cherry!
I like date!

On each pass through the loop, the variable fruit takes on the value of the next item in the list. Python handles all the indexing behind the scenes.

You can also loop with indices if you need the position:

1
2
for i in range(len(fruits)):
    print(f"Item {i}: {fruits[i]}")
1
2
3
4
Item 0: apple
Item 1: banana
Item 2: cherry
Item 3: date

The Enumerate Function

That range(len(...)) pattern works, but Python has a much cleaner solution: the enumerate function. It gives you both the index and the value at the same time:

1
2
3
4
fruits = ["apple", "banana", "cherry", "date"]

for index, fruit in enumerate(fruits):
    print(f"{index}: {fruit}")
1
2
3
4
0: apple
1: banana
2: cherry
3: date

You can even start the count at a different number:

1
2
for rank, fruit in enumerate(fruits, start=1):
    print(f"#{rank}: {fruit}")
1
2
3
4
#1: apple
#2: banana
#3: cherry
#4: date

enumerate() is a favorite among Python programmers. Whenever you need both the position and the value during a loop, reach for enumerate() instead of range(len(...)).

Diagram: List Traversal Animator

List Traversal Animator

Type: microsim sim-id: list-traversal-animator
Library: p5.js
Status: Specified

Bloom Level: Understand (L2) Bloom Verb: trace, explain

Learning Objective: Students will be able to trace the execution of a for loop over a list and predict the output for each iteration.

Purpose: An animated step-through tool that visually shows a pointer moving through a list as a for loop executes, displaying the current variable values and output at each step.

Canvas layout: - Top section: Title "List Traversal Animator" - Left panel: Python code with the for loop, with the current line highlighted - Center panel: A visual row of list items with a pointer arrow indicating the current element - Right panel: Output console showing printed lines accumulating - Bottom section: Variable watch panel showing the current value of the loop variable and index

Code examples (selectable via tabs): 1. Basic for loop: for fruit in fruits: print(fruit) 2. With enumerate: for i, fruit in enumerate(fruits): print(f"{i}: {fruit}") 3. With condition: for fruit in fruits: if len(fruit) > 5: print(fruit)

Interactive controls: - "Step" button: Advance one iteration - "Auto Play" button: Animate all iterations with a 1-second delay - "Reset" button: Return to the start - Speed slider: Adjust animation speed - Tab selector to switch between code examples

Visual elements: - Arrow pointer slides from one box to the next during each iteration - Current box glows yellow - Code panel highlights the active line - Output console scrolls as lines are added - Variable watch updates in real-time

Visual style: Split-panel layout with code on left, visual in center, output on right Color scheme: Code panel in dark theme, visual list in light pastels, output in monospace green-on-black Responsive: Panels stack vertically on narrow screens

Instructional Rationale: Step-by-step animation makes the abstract "iteration" concept concrete by showing exactly which element is being accessed on each pass. The variable watch panel reveals what's happening behind the scenes. Multiple code examples let students compare different traversal patterns side by side.

List Unpacking

Sometimes you know exactly how many items are in a list, and you want to assign each one to its own variable in a single line. That's called list unpacking (also known as destructuring):

1
2
3
4
coordinates = [42.36, -71.06]
latitude, longitude = coordinates
print(latitude)    # 42.36
print(longitude)   # -71.06

The number of variables on the left must match the number of items in the list, or you'll get an error:

1
2
a, b, c = [1, 2]       # ValueError: not enough values to unpack
a, b = [1, 2, 3]       # ValueError: too many values to unpack

Unpacking is great for swapping values without a temporary variable:

1
2
3
4
x = 10
y = 20
x, y = y, x        # Swap!
print(x, y)         # 20 10

You can also use the * operator to capture "the rest" of the items:

1
2
3
4
5
6
7
8
first, *rest = [1, 2, 3, 4, 5]
print(first)    # 1
print(rest)     # [2, 3, 4, 5]

first, *middle, last = [1, 2, 3, 4, 5]
print(first)    # 1
print(middle)   # [2, 3, 4]
print(last)     # 5

Monty says: Let's code this!

Monty List unpacking is especially handy when a function returns multiple values as a list or tuple. Instead of accessing each value by index, you can unpack them into clear, descriptive variable names. Readable code is happy code!

The Zip Function

The zip function combines two (or more) lists element by element, pairing up items at the same index. It's like a zipper on a jacket — it links two sides together, tooth by tooth.

1
2
3
4
5
names = ["Alice", "Bob", "Charlie"]
scores = [92, 85, 78]

for name, score in zip(names, scores):
    print(f"{name}: {score}")
1
2
3
Alice: 92
Bob: 85
Charlie: 78

zip() creates pairs (technically tuples) from corresponding items:

1
2
paired = list(zip(names, scores))
print(paired)  # [('Alice', 92), ('Bob', 85), ('Charlie', 78)]

You can zip more than two lists:

1
2
3
4
5
6
names = ["Alice", "Bob", "Charlie"]
scores = [92, 85, 78]
grades = ["A", "B", "C+"]

for name, score, grade in zip(names, scores, grades):
    print(f"{name} scored {score} ({grade})")
1
2
3
Alice scored 92 (A)
Bob scored 85 (B)
Charlie scored 78 (C+)

If the lists have different lengths, zip() stops at the shortest one:

1
2
3
short = [1, 2]
long = [10, 20, 30, 40]
print(list(zip(short, long)))  # [(1, 10), (2, 20)]

Diagram: Zip Function Visualizer

Zip Function Visualizer

Type: microsim sim-id: zip-function-visualizer
Library: p5.js
Status: Specified

Bloom Level: Understand (L2) Bloom Verb: illustrate, explain

Learning Objective: Students will be able to use the zip function to combine multiple lists element by element and predict the output of zip operations.

Purpose: An animated visualization that shows how zip() pairs up elements from two or three lists, with a zipper metaphor.

Canvas layout: - Top section: Title "Zip Function Visualizer" - Two (or three) vertical columns representing input lists, with items as labeled boxes - A central "zipper" animation zone - Below the zipper: the output — a row of paired tuples - Editable input fields to customize list contents - Toggle: "2 Lists" / "3 Lists"

Interactive elements: - "Zip!" button: Animates the pairing process — items from each list slide toward the center and merge into tuple boxes - Editable text fields for each list's contents (comma-separated) - A "Different Lengths" toggle to demonstrate truncation behavior - Step mode: Pair one element at a time with the "Step" button

Animation sequence: 1. Items from corresponding positions glow and slide toward center simultaneously 2. They merge into a tuple box at the center 3. The tuple slides down into the output row 4. Repeat for each pair 5. If lists have different lengths, remaining items in the longer list are grayed out with a "skipped" label

Visual style: Zipper teeth metaphor with interlocking shapes, smooth slide animations Color scheme: List 1 in blue, List 2 in green, List 3 in orange; paired tuples in purple Responsive: Columns stack and resize for different window widths

Instructional Rationale: The zipper metaphor makes the pairing behavior intuitive and memorable. Animating the merge step-by-step reveals the element-by-element correspondence that defines zip(). Showing the truncation behavior for unequal lengths prevents a common source of bugs. Editable inputs let students test their own data.

Common Patterns and Recipes

Before we wrap up, here are some everyday patterns you'll use with lists all the time. Think of these as recipes you can pull out whenever you need them.

Finding the sum and average:

1
2
3
4
scores = [85, 92, 78, 95, 88]
total = sum(scores)
average = total / len(scores)
print(f"Average: {average}")  # Average: 87.6

Finding the minimum and maximum:

1
2
print(min(scores))   # 78
print(max(scores))   # 95

Checking membership:

1
2
3
4
fruits = ["apple", "banana", "cherry"]
print("banana" in fruits)      # True
print("grape" in fruits)       # False
print("grape" not in fruits)   # True

Concatenating lists:

1
2
3
4
list1 = [1, 2, 3]
list2 = [4, 5, 6]
combined = list1 + list2
print(combined)  # [1, 2, 3, 4, 5, 6]

Repeating lists:

1
2
zeros = [0] * 5
print(zeros)  # [0, 0, 0, 0, 0]

Converting between strings and lists:

1
2
3
4
5
6
7
8
# String to list of words
sentence = "Python lists are awesome"
words = sentence.split()
print(words)  # ['Python', 'lists', 'are', 'awesome']

# List of words back to string
joined = " ".join(words)
print(joined)  # Python lists are awesome

Monty says: You've got this!

Monty You just leveled up big time! Lists are the backbone of Python programming, and you now know how to create them, index them, slice them, modify them, sort them, loop through them, and even nest them. In the next chapter, we'll explore advanced list operations that build on everything you learned here. Keep it up, coder!

Key Takeaways

  • A list is an ordered, mutable collection of items enclosed in square brackets [].
  • Indexing starts at 0. Use negative indices to count from the end (-1 is the last item).
  • Slicing with list[start:stop:step] extracts a sublist without modifying the original.
  • Lists are mutable — you can change, add, and remove items after creation.
  • Key list methods: append() adds to the end, insert() adds at a position, remove() deletes by value, pop() deletes by index and returns the item, sort() orders items, reverse() flips the order.
  • List comprehensions create lists concisely: [expression for item in iterable if condition].
  • Nested lists (lists of lists) represent 2D data like grids and tables. Access elements with double indexing: grid[row][col].
  • Traverse lists with for loops. Use enumerate() when you need both the index and value.
  • List unpacking assigns list items to individual variables in one line.
  • The zip() function combines multiple lists element by element into pairs.
Check Your Understanding: What does fruits[1:4] return if fruits = ['apple', 'banana', 'cherry', 'date', 'elderberry']?

It returns ['banana', 'cherry', 'date']. Remember, slicing goes from the start index up to (but not including) the stop index. So index 1 through index 3 are included.

Check Your Understanding: What's the difference between list.sort() and sorted(list)?

list.sort() modifies the original list in place and returns None. sorted(list) creates and returns a new sorted list, leaving the original unchanged. Use sort() when you don't need the original order anymore; use sorted() when you want to keep the original list intact.

Check Your Understanding: What does this list comprehension produce: [x * 2 for x in range(5) if x % 2 == 0]?

It produces [0, 4, 8]. Here's the breakdown: range(5) gives [0, 1, 2, 3, 4]. The if x % 2 == 0 filter keeps only the even numbers: [0, 2, 4]. Then x * 2 doubles each one: [0, 4, 8].