The idea
So far each variable has held one value. But data comes in groups: all the products in a category, every order today, the last seven days of revenue. A list holds many values, in order, under one name.
cities = ["Jakarta", "Bandung", "Surabaya"]
daily_orders = [12, 9, 15, 7, 11]
print(cities)
print(len(daily_orders))
['Jakarta', 'Bandung', 'Surabaya']
5
A list is written with square brackets, with items separated by commas. len() tells you how many items it has. A list can hold any type, even a mix, but in practice a good list holds one kind of thing: all prices, or all names.
A list is a numbered row of lockers. Each locker has a number (starting at 0) and holds one item. You can open a locker by its number, add lockers at the end, or take one out.
Indexing: getting one item
Each item has a position, its index, starting from 0, exactly like the characters of a string:
cities = ["Jakarta", "Bandung", "Surabaya", "Medan"]
print(cities[0])
print(cities[2])
print(cities[-1])
print(cities[-2])
Jakarta
Surabaya
Medan
Surabaya
Negative indexes count from the end: -1 is the last item, -2 the second-to-last. Ask for an index that doesn't exist and Python stops:
print(cities[4])
IndexError: list index out of range
A list of 4 items has indexes 0 to 3. Off-by-one mistakes like this are the classic list bug.
Slicing: getting a range
A slice gives you a new list with part of the original, using the same start:stop rule you learned for strings: from start up to, but not including, stop.
revenue = [1693, 1957, 1517, 4227, 2552, 1680] # thousands of Rupiah, Jan-Jun
print(revenue[0:3]) # first quarter
print(revenue[3:]) # second quarter
print(revenue[-2:]) # last two months
print(revenue[::2]) # every second month
[1693, 1957, 1517]
[4227, 2552, 1680]
[2552, 1680]
[1693, 1517, 2552]
The optional third number is the step: [::2] takes every second item. [::-1] is a handy idiom that gives a reversed copy.
Lists can change
Here's a big difference from strings. A list of today's stock levels isn't something you build once and leave alone: items get sold, deliveries come in, a typo needs fixing. So unlike strings, lists are mutable, which means you can change them in place without making a new list. To replace one item, assign to its index:
stock = [24, 12, 80]
stock[1] = 15 # replace an item
print(stock)
[24, 15, 80]
Adding and removing items
Lists come with methods for adding and removing. Unlike string methods, most of these change the list itself and return None:
basket = ["Kopi Susu", "Roti Bakar"]
basket.append("Teh Tarik") # add to the end
basket.insert(0, "Air Mineral") # add at a position
print(basket)
basket.remove("Roti Bakar") # remove the first matching value
last = basket.pop() # remove and return the last item
print(basket, last)
['Air Mineral', 'Kopi Susu', 'Roti Bakar', 'Teh Tarik']
['Air Mineral', 'Kopi Susu'] Teh Tarik
| Method | What it does |
|---|---|
.append(x) | adds x to the end |
.insert(i, x) | inserts x at index i |
.extend(other) | adds every item from another list |
.remove(x) | removes the first item equal to x (error if missing) |
.pop() / .pop(i) | removes and returns the last item, or the one at i |
Because .append() changes the list and returns None, writing basket = basket.append("Teh") replaces your list with None. Just call basket.append("Teh") on its own line. This is the opposite of string methods, where you must keep the result.
Searching
With a list of customer ratings, you'll want to ask things like "did anyone give us a 4.8?", "how many did?" and "where's the first one?". There's a tool for each question:
ratings = [4.6, 4.5, 4.8, 4.3, 4.8]
print(4.8 in ratings)
print(ratings.count(4.8))
print(ratings.index(4.8))
True
2
2
in asks whether a value is in the list, .count() counts it, and .index() gives the position of its first appearance.
Sorting
There are two ways to sort, and the difference matters:
prices = [95000, 65000, 110000, 55000]
cheapest_first = sorted(prices)
print(cheapest_first)
print(prices)
prices.sort(reverse=True)
print(prices)
[55000, 65000, 95000, 110000]
[95000, 65000, 110000, 55000]
[110000, 95000, 65000, 55000]
sorted(list)returns a new sorted list and leaves the original alone.list.sort()sorts the list in place and returnsNone.- Both take
reverse=Truefor largest-first.
Use sorted() when you still need the original order, and .sort() when you don't.
Handy built-ins for number lists
A list of numbers, like orders per day, is usually there so you can summarise it: the total for the week, the slowest day, the busiest day, the average. Python's built-in functions take a whole list and give you those answers directly, with no loop needed:
daily_orders = [12, 9, 15, 7, 11]
print(sum(daily_orders), min(daily_orders), max(daily_orders))
print(sum(daily_orders) / len(daily_orders))
54 7 15
10.8
sum(), min() and max() work on any list of numbers, and sum() / len() gives the average.
Lists of lists
An item can itself be a list, which gives you a simple table: a list of rows.
orders = [
["Ayu", "Jakarta", 285000],
["Budi", "Bandung", 960000],
]
print(orders[1])
print(orders[1][2])
['Budi', 'Bandung', 960000]
960000
orders[1] is the second row, and orders[1][2] is the third item of that row. This works, but as soon as you need named fields, a dictionary (coming soon) or a pandas DataFrame is much clearer than remembering that index 2 means "total".
Copying a list
Assigning a list to a new name does not copy it. Both names point to the same list:
original = [1, 2, 3]
alias = original
alias.append(4)
print(original)
copy = original.copy()
copy.append(5)
print(original, copy)
[1, 2, 3, 4]
[1, 2, 3, 4] [1, 2, 3, 4, 5]
When you want an independent list, use .copy() (or a full slice, original[:]).
Why this matters for clean code
Name lists in the plural (cities, prices, orders) so cities[0] reads as "the first city". Keep one kind of thing per list. And know which operations change a list and which make a new one: most list bugs come from changing a list you thought was a copy, or from storing the None that an in-place method returned.
Recap
- A list is an ordered, changeable collection:
items = [a, b, c].len(items)counts them. - Index from 0, negative from the end. Out-of-range indexes raise
IndexError. - Slices
items[start:stop:step]return a new list. .append,.insert,.extend,.remove,.popchange the list in place.sorted(items)returns a new list;items.sort()sorts in place.sum,min,max,in,.count,.indexanswer common questions.b = ashares one list;b = a.copy()makes a separate one.