Lists
Keep many values in order, then index, slice and change them.
Why it matters
Data comes in collections. Rows from an export. A batch of headlines to score. The documents you'll search in a RAG system. The examples a model trains on. And when you call an LLM, the conversation you send is literally a list of messages. Lists are Python's usual way to hold many things in order.
What you'll be able to do
- Create a list and read items and slices from it by position
- Add, change and remove items
- Summarize a list with len, sum, min, max and sorted
- Explain why two names can point at the same list, and make a real copy
What it covers
- Many values, in order
- Indexing and slicing
- Changing a list
- Asking questions about a list
- Two names, one list
- Worked example: a week of signups
- Methods that change the list, and methods that don't
- A list can hold anything
Many values, in order
Think of a shopping list: several items, written in order, one after another. A Python list is the same. It holds several values in a fixed order. Write it with square brackets and commas:
channels = ["search", "display", "video", "email", "social"] daily_clicks = [412, 388, 501, 467, 590] empty = [] print(channels) print(len(channels)) # how many items print(len(empty))
A list can hold any type of value, even a mix. In practice, most lists hold one kind of thing: all names, or all numbers. Lists are often built from other data, as you saw with .split() in the strings lesson.
Indexing and slicing
Lists use the same positions as strings:
- the first item is at index
0, - the last is at
-1, - a slice
[start:stop]stops beforestop.
The difference is that each position holds a whole value, not a single character.
Same rules as strings: a slice stops before the stop index, and negative indexes count from the end. A slice of a list is a new, shorter list.
channels = ["search", "display", "video", "email", "social"] print(channels[0]) print(channels[-1]) print(channels[1:3]) print(channels[:2])
As with strings, asking for a position that doesn't exist, such as channels[5] here, raises an IndexError.
channels = ["search", "display", "video", "email", "social"] print(channels[-2])
Show the answer
-1 is the last item, 'social', so -2 is the one before it: email.
Changing a list
Strings can't be changed in place, but lists can. You can replace an item by giving its index a new value. And you can add or remove items with methods. These methods change the list itself, so there's no need to store a result.
| Code | Effect |
|---|---|
items[0] = "paid search" | replace the item at index 0 |
items.append(x) | add x to the end |
items.insert(0, x) | add x at index 0, shifting the rest along |
items.extend(other_list) | add every item from another list |
items.remove(x) | remove the first item equal to x |
items.pop() | remove the last item and give it back (pop(0) takes the first) |
queue = ["Spring sale", "New arrivals"] queue.append("Customer stories") queue.insert(0, "Welcome email") print(queue) queue[1] = "Spring sale (final)" queue.remove("New arrivals") sent = queue.pop(0) print("Sent:", sent) print("Still queued:", queue)
.remove() raises a ValueError if the item isn't in the list.
Asking questions about a list
daily_spend = [310.5, 288.0, 402.75, 365.2, 290.0] print("Days:", len(daily_spend)) print("Total:", sum(daily_spend)) print("Lowest:", min(daily_spend), "Highest:", max(daily_spend)) print("Average:", round(sum(daily_spend) / len(daily_spend), 2)) tags = ["seo", "email", "ads"] print("email" in tags) # True or False print(tags.count("seo")) # how many times it appears print(tags.index("ads")) # where it first appears
sum() only works on numbers. min() and max() also work on strings, comparing them in alphabetical order.
Sorting
There are two ways to sort, and the difference catches everyone at least once:
sorted(items)gives you a new sorted list and leaves the original alone.items.sort()sorts the list in place and returnsNone(Python's value for "nothing").
Both accept reverse=True for largest-first order.
scores = [72, 95, 64, 88] ranked = sorted(scores, reverse=True) print(ranked) print(scores) # unchanged scores.sort() print(scores) # now changed result = scores.sort() print(result) # None: never write scores = scores.sort()
scores = [72, 95, 64] top = sorted(scores, reverse=True) print(scores[0], top[0])
Show the answer
72 95
sorted() gives back a new list and leaves scores alone, so scores[0] is still 72. The new list top starts with the largest, 95.
Two names, one list
Giving a list a second name does not copy it. Picture one shared document with two people's names on it: an edit by either person shows up for both. Both names refer to the same list, so a change through one name shows up through the other:
approved = ["Headline A", "Headline B"] backup = approved # same list, two names backup.append("Headline C") print(approved) # it changed too real_copy = approved.copy() # a separate list with the same items real_copy.append("Headline D") print(approved) # unchanged this time print(real_copy)
This is different from the numbers and strings you've used so far. You can't change those in place, so sharing them between names never causes surprises. Lists can change in place, so sharing matters. When you want a separate list, use .copy() (or the slice [:]).
Lists inside lists
An item can itself be a list. That's a natural way to hold a table, with one inner list per row. Use two indexes: the first picks the row, and the second picks the item in it.
rows = [
["cmp_101", "search", 5000],
["cmp_102", "display", 2000],
]
print(rows[1])
print(rows[1][2])
Worked example: a week of signups
Signups from a landing page, Monday to Sunday. Compare weekdays with the weekend and find the best day.
signups = [42, 38, 51, 47, 60, 22, 19] # Monday to Sunday weekdays = signups[:5] weekend = signups[5:] print("Total:", sum(signups)) print("Best day:", max(signups)) print("Weekday average:", sum(weekdays) / len(weekdays)) print("Weekend average:", sum(weekend) / len(weekend)) print("High to low:", sorted(signups, reverse=True)) print("Order kept:", signups)
Slicing splits the week into two new lists without changing signups. Average is always sum / len, so the same expression works for any length of list. Using sorted() instead of .sort() leaves the day order intact, which matters here because position 0 means Monday. Sorting in place would have lost which number belonged to which day.
a = [1, 2, 3] b = a b.append(4) print(len(a))
Show the answer
4
a and b are two names for the same list, so appending through b makes that one list [1, 2, 3, 4]. Its length, read through a, is 4.
Methods that change the list, and methods that don't
Some list operations change the list and give back nothing. Others leave it alone and give back a new one. Mixing them up causes one of the most common bugs in Python.
scores = [3, 1, 2] result = scores.sort() # changes scores, gives back None print(scores, result) scores = [3, 1, 2] result = sorted(scores) # leaves scores alone, gives back a new list print(scores, result)
So x = x.sort() throws your list away and leaves x holding None. Use x.sort() on its own line, or x = sorted(x). The same applies to .append(), .remove() and .reverse(): call them on their own line and don't assign the result.
append, plus and remove
.append() adds one item to this list. a + b builds a new list and leaves both originals alone. If you write a + [5] and never save it, nothing changes.
.remove() takes a value, not a position. items.remove(2) removes the first item equal to 2, wherever it is. To remove by position, use .pop(2), which also hands you the item it took out.
Getting a real copy
b = a doesn't copy anything: it gives the same list a second name, as you saw above. When you need an independent list, ask for one with b = a.copy() or b = list(a).
This matters most when you pass lists around later in the course. If a part of your program quietly changes a list that another part is still using, the bug can appear far from its cause. When two values change together and you can't see why, ask whether they're the same list.
A list can hold anything
A list can hold numbers and text together, and even other lists. Python won't object. Sorting a mixed list fails, however, since Python won't guess whether 3 comes before "apple". Keep one kind of item per list, and sorting stays easy and predictable.
Practice what you just read
- 9 code examples you can edit and run
- a practice exercise that checks your code
- a 6-question quiz
- 5 review cards for spaced repetition
Try a quiz question
What does this print?
x = [3, 1, 2]
x = x.sort()
print(x)