A list is Python’s most-used data structure — an ordered collection of items that you can grow, shrink, and change. Lists hold the values of a column in a dataset, the lines of a file, the predictions of a model, the names in a directory. They are everywhere.

Creating a list

fruits: list[str] = ["apple", "banana", "cherry"]
scores: list[int] = [85, 92, 78, 95, 60]
mixed: list[object] = [1, "hello", 3.14, True]
empty: list[int] = []

A list:

  • Uses square brackets [ ].
  • Items are separated by commas.
  • Items can be any type — even other lists.
  • The type hint list[T] says what kind of items are inside.

Accessing items — indexing

Like strings, list positions start at 0:

fruits: list[str] = ["apple", "banana", "cherry"]

print(fruits[0])    # 'apple'
print(fruits[1])    # 'banana'
print(fruits[-1])   # 'cherry'  (last)
print(fruits[-2])   # 'banana'  (second to last)

Out-of-range positions raise IndexError.

Slicing

The same slice syntax as strings:

nums: list[int] = [10, 20, 30, 40, 50]

print(nums[1:4])     # [20, 30, 40]
print(nums[:3])      # [10, 20, 30]
print(nums[2:])      # [30, 40, 50]
print(nums[::-1])    # [50, 40, 30, 20, 10]  — reversed
print(nums[::2])     # [10, 30, 50]          — every second item

A slice creates a new list. The original is unchanged.

Lists are mutable

Unlike strings, you can change a list’s contents in place:

nums: list[int] = [1, 2, 3]
nums[0] = 99
print(nums)   # [99, 2, 3]

Adding items

fruits: list[str] = ["apple"]

fruits.append("banana")            # add one item at the end
print(fruits)                      # ['apple', 'banana']

fruits.insert(0, "kiwi")           # insert at a position
print(fruits)                      # ['kiwi', 'apple', 'banana']

fruits.extend(["mango", "pear"])   # add many items at the end
print(fruits)                      # ['kiwi', 'apple', 'banana', 'mango', 'pear']

# you can also use +
combined: list[str] = fruits + ["grape"]

append adds one item. extend adds each item from another collection.

# the difference matters
a: list[str] = ["x"]
a.append(["y", "z"])     # ['x', ['y', 'z']]  ← nested!
a = ["x"]
a.extend(["y", "z"])     # ['x', 'y', 'z']    ← flat

Removing items

nums: list[int] = [10, 20, 30, 40, 50]

nums.remove(30)        # removes the first occurrence of 30
print(nums)            # [10, 20, 40, 50]

last: int = nums.pop()      # removes and returns the last item
print(last, nums)           # 50 [10, 20, 40]

second: int = nums.pop(1)   # removes and returns position 1
print(second, nums)         # 20 [10, 40]

del nums[0]            # removes by position (no return)
print(nums)            # [40]

nums.clear()           # empties the list
print(nums)            # []

Looping over a list

fruits: list[str] = ["apple", "banana", "cherry"]

for fruit in fruits:
    print(fruit)

# with index
for index, fruit in enumerate(fruits):
    print(f"{index}: {fruit}")

Sorting

nums: list[int] = [3, 1, 4, 1, 5, 9, 2, 6]

nums.sort()                # in place — changes nums
print(nums)                # [1, 1, 2, 3, 4, 5, 6, 9]

nums.sort(reverse=True)    # descending
print(nums)                # [9, 6, 5, 4, 3, 2, 1, 1]

# sorted() returns a NEW sorted list, leaves the original alone
original: list[int] = [3, 1, 4, 1, 5]
ordered: list[int] = sorted(original)
print(original, ordered)   # [3, 1, 4, 1, 5] [1, 1, 3, 4, 5]

You can sort by a custom key:

words: list[str] = ["banana", "fig", "apple", "kiwi"]
by_length: list[str] = sorted(words, key=len)
print(by_length)   # ['fig', 'kiwi', 'apple', 'banana']

Useful list operations

nums: list[int] = [5, 2, 8, 2, 1]

print(len(nums))         # 5
print(sum(nums))         # 18
print(min(nums))         # 1
print(max(nums))         # 8
print(2 in nums)         # True
print(nums.count(2))     # 2
print(nums.index(8))     # 2 — position of the first 8
nums.reverse()           # in place
print(nums)              # [1, 2, 8, 2, 5]

Copying a list

This is a common gotcha:

a: list[int] = [1, 2, 3]
b: list[int] = a          # b points to the SAME list
b.append(4)
print(a)                  # [1, 2, 3, 4]   ← changed!

To get an independent copy:

a: list[int] = [1, 2, 3]
b: list[int] = a.copy()          # or list(a) or a[:]
b.append(4)
print(a)                          # [1, 2, 3]
print(b)                          # [1, 2, 3, 4]

List comprehensions — a teaser

Building a list with a loop:

squares: list[int] = []
for n in range(1, 6):
    squares.append(n * n)
print(squares)   # [1, 4, 9, 16, 25]

The same thing as a list comprehension:

squares: list[int] = [n * n for n in range(1, 6)]

One line, just as clear, and faster. We’ll cover comprehensions properly in the last lesson of this section.

What’s next

Lists are the workhorse. Next, tuples — the close cousin that can’t be changed once it’s made.

Toggle theme (T)