Section · 01
What a list actually is
A list is an ordered collection of values, held in a single variable, that you can change after creation. That’s it. Three traits, in that order: ordered, collection, changeable.
You write a list with square brackets and commas between the values:
groceries = ["bread", "eggs", "olive oil", "coffee"]
high_scores = [98, 87, 94, 71, 100]
mixed = ["York", 2025, True, 3.14]Notice the last one — Python lists don’t care if you mix types. A string, an int, a bool, and a float can sit in the same list. That’s different from arrays in Java or C, where every element has to be the same type.
Section · 02
Reading: indexes and slices
You read a value out of a list with list_name[index]. Indexes start at zero, not one. This is the single most-common source of off-by-one bugs in Python.
groceries = ["bread", "eggs", "olive oil", "coffee"]
groceries[0] # "bread" (first)
groceries[1] # "eggs"
groceries[3] # "coffee" (last, since there are 4 items)
groceries[4] # IndexError — there is no index 4Negative indexes count from the end, which is useful when you don’t know how long the list is:
groceries[-1] # "coffee" (last)
groceries[-2] # "olive oil" (second to last)You can also grab a chunk of the list with slicing. The syntax is list_name[start:stop], and stop is exclusive — Python gives you everything from start up to but not including stop:
groceries[1:3] # ["eggs", "olive oil"] (indexes 1 and 2)
groceries[:2] # ["bread", "eggs"] (start defaults to 0)
groceries[2:] # ["olive oil", "coffee"] (stop defaults to end)
groceries[:] # a full copy of the listThat last one — list[:]— is the simplest way to get a shallow copy. Skip it and you’re passing references around, which is mistake #3 below.
Section · 03
Changing: lists are mutable
Lists are mutable. You can change them after they exist. That’s the whole point — if data won’t change, use a tuple. Five things you’ll do constantly:
groceries = ["bread", "eggs", "olive oil"]
# 1. Replace by index
groceries[0] = "sourdough"
# ["sourdough", "eggs", "olive oil"]
# 2. Append to the end
groceries.append("coffee")
# ["sourdough", "eggs", "olive oil", "coffee"]
# 3. Insert at a specific index
groceries.insert(1, "butter")
# ["sourdough", "butter", "eggs", "olive oil", "coffee"]
# 4. Remove a known value
groceries.remove("eggs")
# ["sourdough", "butter", "olive oil", "coffee"]
# 5. Remove by index (and get the value back)
last = groceries.pop()
# last = "coffee"
# groceries = ["sourdough", "butter", "olive oil"]append adds one item to the end. If you want to merge another list into this one, use extend instead — that’s mistake #1 below.
Section · 04
Three mistakes everyone makes
1. Using `append` when you meant `extend`
nums = [1, 2, 3]
nums.append([4, 5]) # [1, 2, 3, [4, 5]] — nested!
nums.extend([4, 5]) # [1, 2, 3, 4, 5] — flatappend(x) adds x as a single element. If x is a list, you get a list inside a list. extend(x) unpacks x and adds each item individually.
2. Assigning the result of a mutating method
# WRONG — .sort() returns None, not the sorted list
nums = [3, 1, 4, 1, 5]
nums = nums.sort() # nums is now None
# RIGHT — sort mutates in place
nums = [3, 1, 4, 1, 5]
nums.sort() # nums is now [1, 1, 3, 4, 5]
# OR use sorted(), which returns a new list
nums = [3, 1, 4, 1, 5]
ordered = sorted(nums) # ordered = [1, 1, 3, 4, 5], nums unchangedMethods that change the list in place — .sort(), .append(), .reverse(), .remove() — return None. If you assign the result to a variable, that variable becomes None and you lose your list. Burn this one into your brain.
3. Copying with `=` instead of slicing
original = [1, 2, 3]
copy = original # NOT a copy — same list, two names
copy.append(4)
# original is now [1, 2, 3, 4] — you mutated the original
# Actually copy with slicing or .copy()
copy = original[:] # shallow copy
# or
copy = original.copy() # same thing, clearer name= in Python binds names to objects. It does not copy. Two names pointing at the same list will both see every change. For nested lists you also need to know about copy.deepcopy(), but you can save that for the day you actually hit the bug.