Difficulty: Beginner | Prerequisites: Basic Python syntax, variables, loops
These are the two ordered, sequence-based data structures built into Python. If you understand how indexing, slicing, and iteration work on one of them, you already know most of how the other works. The key difference is mutability: lists let you change their contents after creation, tuples do not. This distinction drives which methods each type supports and when you would choose one over the other.
Lists and tuples are both ordered sequences that support indexing, slicing, and iteration. Lists are mutable (you can add, remove, and change elements after creation), while tuples are immutable (once created, their contents are fixed). Use a list when you need a collection that changes over time, and a tuple when you want to group related values that should stay together unchanged.
List
A built-in Python data structure that stores an ordered, mutable sequence of values. Elements can be of any type, and different types can coexist in the same list.
In simple terms, think of it as a numbered row of boxes you can rearrange, add to, or swap out at any time.
Tuple
A built-in Python data structure that stores an ordered, immutable sequence of values. Like lists, elements can be of any type.
Think of it as a sealed row of boxes: you can look at what is inside each one, but you cannot change, add, or remove anything.
Mutable
A property meaning the object's contents can be changed after it is created. Lists, sets, and dictionaries are mutable.
In simple terms, "mutable" means "changeable in place."
Immutable
A property meaning the object's contents cannot be changed after it is created. Tuples and strings are immutable.
In simple terms, once you create it, it is locked. You can read it, but you cannot edit it.
Indexing
Accessing a specific element in a sequence by its position number. Python uses zero-based indexing, so the first element is at index 0. Negative indexing counts from the end: -1 is the last element, -2 is the second to last, and so on.
Think of it as looking up a specific seat number in a row.
Slicing
Extracting a sub-sequence from a sequence using the syntax sequence[start:end]. Returns elements from the start index up to (but not including) the end index.
In simple terms, slicing lets you copy out a chunk of a list or tuple by saying where to start and where to stop.
Iterable
Any Python object you can loop over with a for loop. Lists, tuples, sets, dictionaries, and strings are all iterable.
If you can write for item in thing, then thing is iterable.
A list stores an ordered collection of values, written with square brackets: my_list = [1, 2, 3]
Elements can be any type, and you can mix types in the same list: mixed = [1, "hello", 3.14, True]
An empty list is created with [] or list()
Access elements by position using list_name[index]
Indexing starts at 0: the first element is list[0], the second is list[1]
Negative indexing counts from the end: list[-1] is the last element, list[-2] is second to last
Accessing an index outside the valid range raises an IndexError
Because lists are mutable, you can also assign to an index: list[0] = "new_value"
Extract a sub-list with list_name[start:end]
start defaults to 0 if omitted; end defaults to the length of the list
The slice includes start but excludes end
Returns a new list; the original is not changed
Method 1: for-each loop (access elements only, no index)
for elem in my_list: then operate on elem
For nested lists: for elem in my_list: then for item in elem:
Method 2: index-based loop (access both index and element)
for i in range(len(my_list)): then use my_list[i]
For nested lists: for i in range(len(my_list)): then for j in range(len(my_list[i])):
Built-in functions: len(list) returns the number of elements, sum(list) totals numeric elements
+ operator: concatenates two lists into a new list
* operator: repeats a list a given number of times
in operator: item in list evaluates to True if item is found, False otherwise
list.append(item) adds item to the end of the list
list.insert(index, item) inserts item at the specified index; existing elements shift right
list.remove(item) removes the first occurrence of item; raises ValueError if not found
list.index(item) returns the index of the first element equal to item; raises ValueError if not found
list.sort() sorts the list in ascending order (in place)
list.reverse() reverses the list order (in place)
list.clear() removes all elements from the list
A tuple stores an ordered collection of values, written with parentheses: my_tuple = (1, 2, 3)
Typically used to group varied information about a single object (e.g. a student record: ("Alice", 21, 3.8))
Elements can be any type, and you can mix types
When you have different data types describing one entity, a tuple is the conventional choice
Access elements by position using tuple_name[index]
Same zero-based and negative indexing rules as lists
Because tuples are immutable, you cannot assign to an index: my_tuple[0] = "new" raises a TypeError
Built-in functions: len(), sum()
Indexing (read-only)
Slicing
+ and * operators (these return new tuples)
in operator
tuple.index(item) returns the index of the first match
Iteration with both for-each and index-based for loops
Because tuples are immutable, you cannot:
Assign to an index to change a value
Use append(), insert(), remove(), sort(), reverse(), or clear()
If you need to "change" a tuple, you create a new one with the desired values.
Use a tuple when the data should not change after creation (coordinates, database rows, function return values with multiple items)
Use a list when you need to add, remove, or reorder elements over time
Students often think indexing starts at 1. It does not. The first element is always at index 0.
Students sometimes assume list.sort() returns a new sorted list. It does not. It sorts the list in place and returns None. If you write result = my_list.sort(), result will be None.
Students often confuse tuples and lists because the syntax is so similar. The distinguishing rule is simple: parentheses () for tuples, square brackets [] for lists, and tuples cannot be changed after creation.
Students sometimes believe list.remove(item) removes all occurrences. It removes only the first occurrence. To remove all, you would need a loop.
⚠️ Know which operations raise errors: accessing an out-of-range index (IndexError), removing a non-existent item (ValueError), and assigning to a tuple index (TypeError).
⚠️ Be able to trace through nested loop iteration on a 2D list. This is a common exam question pattern.
⚠️ Understand the difference between list.append() (adds one element) and list.insert() (adds at a specific position, shifts everything else).
⚠️ Slicing boundaries are a frequent source of off-by-one errors. Remember: the end index is excluded.
True or False: You can change the value of an element in a tuple after it has been created.
False. Tuples are immutable.
Fill in the blank: my_list = [10, 20, 30, 40]. The value of my_list[-2] is ___.
True or False: my_list[1:3] returns three elements.
False. It returns two elements (at indices 1 and 2). The end index is excluded.
Fill in the blank: To add an item to the end of a list, use the ___ method.
append().
True or False: Lists and tuples both support the in operator.
True.
Q: Given nums = [5, 10, 15, 20, 25], what does nums[1:4] return?
A: [10, 15, 20]
Q: What is the difference between list.append(x) and list.insert(0, x)?
A: append(x) adds x to the end of the list. insert(0, x) adds x at the beginning (index 0), shifting all existing elements one position to the right.
Q: Why does the following code raise an error? my_tuple = (1, 2, 3) then my_tuple[0] = 10
A: Tuples are immutable. You cannot assign a new value to an existing index in a tuple. This raises a TypeError.
Q: What is the output of len([1, [2, 3], 4])?
A: 3. The list contains three elements: the integer 1, the nested list [2, 3] (which counts as one element), and the integer 4.
Q: Write a for loop that prints every element in a list called items along with its index.
A: for i in range(len(items)): then print(i, items[i])
Lists and tuples connect directly to dictionaries: dictionary keys must be immutable, so tuples can serve as keys but lists cannot. This is one practical reason to understand the mutable/immutable distinction.
Iteration patterns learned here (for-each loops, index-based loops) apply identically to strings, sets, and dictionaries, so mastering them on lists and tuples carries over to every other built-in data structure.
Slicing syntax also works on strings, since strings are sequences too.
Python list, Python tuple, mutable vs immutable, list methods, tuple methods, list indexing, negative indexing, list slicing, zero-based index, append vs insert, list.sort(), list.reverse(), list.remove(), for-each loop, index-based for loop, range(len()), ordered sequence, data structures Python, CS 303E, intro to programming, collection types, list comprehension (related, not covered here)