Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Lists

Lists are ordered, mutable sequences. Use them when position matters or when you want to keep adding and removing items over time.

Think of a list as a numbered row of slots. Slot 0 is the first item, slot 1 is the second, and so on. A list holds one element type, so a list[str] is for strings only.

Creating lists

fruits = ["apple", "banana", "orange"]
tasks: list[str] = []
numbers: list[int] = [1, 2, 3]

Use a literal when you already have values. Use an empty list when you plan to fill it later. If the compiler cannot infer the element type from context, add an annotation.

Lists are dynamic arrays. Appending is cheap most of the time because storage grows in chunks, not one item at a time.

Reading values

items = ["first", "second", "third", "fourth"]

print(items[0])
print(items[-1])
print(items[1:3])
print(len(items))
print("second" in items)
print(items.index("third"))

Indexing starts at 0. Negative indexes count from the end. Slices use the familiar start:stop form and include the start but exclude the stop.

If you are coming from a one-based indexing language, the first item is still at position 0 here.

Updating lists

items = ["first", "second", "third"]

items.append("fourth")
items.insert(1, "new")
items.extend(["fifth", "sixth"])

print(items)
print(items.pop())
print(items.pop(0))
del items[1]

append() adds one item to the end. insert() places an item at a specific index. extend() adds several items from another iterable. pop() removes and returns an item, and del items[i] removes by index without returning anything.

Appends are amortized O(1). Inserting or deleting near the front of a long list is O(n) because elements need to shift. `pop()` is O(1) at the end and O(n) at other positions.

Common utilities

values = [9, 5, 123, 14, 1, 5]

print(sorted(values))
values.reverse()
print(values)
print(values.count(5))

copy_of_values = values.copy()
values.clear()
print(copy_of_values)
print(values)

sorted() returns a new list. reverse() changes the existing list in place. count() scans the whole list and counts matches. copy() makes a shallow copy, which is enough when the elements themselves are simple values.

If the list contains mutable values, a shallow copy only duplicates the outer list. The items inside are still shared.

Iterating over lists

names = ["Ada", "Bjarne", "Grace"]

for name in names:
    print(name)

for i, name in enumerate(names):
    print(i, name)

Iteration gives you each item in order. Use enumerate() when you also need the current index.

List comprehensions

numbers = [1, 2, 3, 4, 5]
squares = [n * n for n in numbers]
evens = [n for n in numbers if n % 2 == 0]

List comprehensions are the compact way to build a new list from an existing iterable. Read them as "make a list of this expression for each item that matches the condition".

Type safety

All items in a list must be of the same type. Mixing types like ["foo", 1, True] will not compile.

strings = ["foo", "bar", "baz"]
numbers = [1, 2, 3, 4, 5]

When a list is empty, give it a type if the surrounding code does not make the element type obvious.