08 - Lists and Tuples
Lists and tuples group values in an order.
A simple picture
A list is an editable row of school lockers. Each locker has an index and can hold a value. A tuple is a sealed row: you can read its values, but you cannot replace its slots.
index: 0 1 2
list: ["red", "blue", "green"]
Lists
A list uses square brackets. Commas separate its items. The list keeps item order, and indexes begin at zero just like string indexes.
marks = [72, 88, 91]
print(marks[0])
print(marks[-1])
Lists can contain values of different types, but a collection is easier to use when its values have a consistent meaning.
marks = [72, 88, 91]
| | |
index 0 1 2
Changing a list
Lists are mutable, so these operations change the existing list:
marks[0] = 75
marks.append(79) # add at the end
marks.insert(1, 80) # add at an index
marks.remove(91) # remove the first matching value
last = marks.pop() # remove and return the last value
remove() searches for a value; pop() removes by index or removes the final item when no index is supplied.
Run each change separately and inspect the list:
colors = ["red", "blue"]
colors.append("green")
print(colors) # ["red", "blue", "green"]
colors.insert(1, "yellow")
print(colors) # ["red", "yellow", "blue", "green"]
removed_color = colors.pop()
print(removed_color) # green
print(colors) # ["red", "yellow", "blue"]
Important differences:
| Operation | Searches by | What happens when missing? | Returned value |
|---|---|---|---|
append(value) |
no search | adds at the end | None |
insert(index, value) |
position | inserts at the requested position | None |
remove(value) |
value | raises ValueError |
None |
pop(index) |
position | raises IndexError |
removed item |
Slicing and copying
List slicing follows the same start:stop:step rule as string slicing. The stop index is not included.
values = [10, 20, 30, 40, 50]
print(values[1:4])
copy_of_values = values[:]
Assigning other = values does not copy the list; both names refer to the same list. Use values.copy() or values[:] for a shallow copy.
Important fact:
other = valuescreates another name for the same list. A change through either name is visible through both names.
first = [10, 20]
second = first
second.append(30)
print(first) # [10, 20, 30]
A shallow copy creates a new outer list. If the list contains inner lists, those inner lists are still shared. This is an optional edge case for nested data:
original = [[1, 2], [3, 4]]
copied = original.copy()
copied[0].append(99)
print(original) # [[1, 2, 99], [3, 4]]
Useful list operations
numbers = [4, 1, 9, 2]
print(len(numbers))
print(sum(numbers))
print(min(numbers), max(numbers))
numbers.sort()
print(numbers)
sort() changes the list. sorted(numbers) returns a new sorted list.
Tuples
Tuples use parentheses and are immutable:
point = (10, 20)
x, y = point
print(x, y)
Use a tuple for a fixed record such as a coordinate, RGB color, or date. A one-item tuple needs a comma: ("Python",).
The comma creates a tuple; parentheses mainly make it easy to read:
not_a_tuple = ("Python")
one_item_tuple = ("Python",)
print(type(not_a_tuple)) # <class 'str'>
print(type(one_item_tuple)) # <class 'tuple'>
Packing and unpacking
date = 2026, 8, 5 # packing
year, month, day = date # unpacking
The number of target names must match the number of values unless starred unpacking is used:
first, *middle, last = [1, 2, 3, 4]
List comprehensions
A comprehension creates a list from a clear rule:
squares = [number ** 2 for number in range(1, 5)]
even_squares = [number ** 2 for number in range(1, 8) if number % 2 == 0]
Write the ordinary loop first if a comprehension feels difficult.
These two programs mean the same thing:
# Ordinary loop
squares = []
for number in range(1, 5):
squares.append(number ** 2)
# Comprehension
squares = [number ** 2 for number in range(1, 5)]
Read the comprehension as: “create number ** 2 for each number in the range.” Use the ordinary loop whenever it communicates the steps more clearly.
Real-world example
marks = [72, 88, 91, 64]
total = sum(marks)
average = total / len(marks)
passed = [mark for mark in marks if mark >= 40]
print(f"Average: {average:.2f}")
print(f"Passed count: {len(passed)}")
Common mistakes
- Using an index that does not exist.
- Confusing
remove(value)andpop(index). - Accidentally sharing a list when a copy was intended.
- Trying to modify a tuple.
- Forgetting that
sort()returnsNonebecause it changes the list in place.
Bug Hunter
Bug 1 — index outside the list
colors = ["red", "blue", "green"]
print(colors[3])
Bug 2 — two names, one list
original = [1, 2]
copied = original
copied.append(3)
print(original)
The programmer expected original to remain [1, 2].
Bug 3 — sort() result
scores = [70, 90, 80]
sorted_scores = scores.sort()
print(sorted_scores)
Show Bug Hunter fixes
# Bug 1: the final valid index is 2.
print(colors[2])
# Bug 2: make a shallow copy of this simple list.
copied = original.copy()
# Bug 3: either sort then print the same list...
scores.sort()
print(scores)
# ...or request a new sorted list.
sorted_scores = sorted(scores)
Optional deeper look: how is a list stored?
A CPython list keeps an ordered array of references to objects. It normally reserves a little extra room so repeated append() operations do not need to rebuild the storage every time. A shallow copy creates a new outer list but still refers to the same nested objects.
Practice
Try these problems on this page. Use a small list by hand before writing the program.
Problems
- Calculate the sum of a list of numbers.
- Find the largest value without
max(). - Count even and odd values.
- Remove duplicates while preserving order.
- Reverse a list without calling
reverse(). - Rotate a list by one position.
- Merge two lists and sort the result.
- Find the second-largest distinct number.
- Unpack a tuple representing a date.
- Build a marks analyzer that displays total, average, highest, and lowest values.
Show hints
- Start at zero and add each item.
- Keep a current largest value.
- Test
number % 2inside a loop. - Use a result list and add an item only when it is not already present.
- Slicing can move through a list backwards.
- Combine the final item with the earlier slice.
- Join the lists before sorting.
- Build a new list containing each value only once, sort it, and select the second-last value.
- Assign tuple values to three names.
- Store and print the four results with clear labels.
Show solution ideas
total = 0and add every item.- Initialize from the first item and compare the rest.
- Maintain
even_countandodd_count. result = []; append only whenitem not in result.values[::-1].values[-1:] + values[:-1].sorted(first + second).- Build
unique_valueswith a loop, sort it, and useunique_values[-2]after checking its length. year, month, day = date_tuple.- Use
sum(),len(),min(), andmax(), then print each result.
Homework
Build a weekly sales analyzer that accepts seven values and reports total sales, average sales, best day, and days below average.
Checkpoint
Given a list of marks, calculate total, average, highest, and lowest values. Explain why a list is more suitable than a tuple if marks can be corrected.