Skip to content
elephantoo

Lists

Lesson 8 of 38 14 min read

Create, slice, modify and sort lists, key functions, unpacking, shallow vs deep copies and common traps.


The list is Python's workhorse collection: an ordered, changeable sequence of values. Shopping carts, rows from a database, lines from a file, search results — they're all lists. This lesson covers creating, reading, changing, sorting and copying lists, plus the pitfalls that catch everyone at least once.

Creating lists#

Python
empty = []
primes = [2, 3, 5, 7, 11]
mixed = ["Ada", 36, True, None]     # allowed, though usually items share a type
nested = [[1, 2], [3, 4]]
letters = list("abc")               # from any iterable
numbers = list(range(1, 6))

print(primes, len(primes))
print(letters, numbers)
Output
[2, 3, 5, 7, 11] 5
['a', 'b', 'c'] [1, 2, 3, 4, 5]

Indexing and slicing#

Lists use the same indexing and slicing rules as strings — zero-based, negative from the end, stop index excluded:

Python
colors = ["red", "orange", "yellow", "green", "blue"]
print(colors[0], colors[-1])
print(colors[1:3])
print(colors[::2])
print(colors[::-1])
print("green" in colors, colors.index("yellow"))
Output
red blue
['orange', 'yellow']
['red', 'yellow', 'blue']
['blue', 'green', 'yellow', 'orange', 'red']
True 2

Unlike strings, lists are mutable, so you can assign to an index or even a slice:

Python
colors = ["red", "orange", "yellow"]
colors[0] = "crimson"
colors[1:3] = ["amber"]        # replace two items with one
print(colors)
Output
['crimson', 'amber']

Adding and removing items#

Python
cart = ["pen"]
cart.append("notebook")             # add one item at the end
cart.extend(["ruler", "eraser"])    # add many items
cart.insert(0, "bag")               # insert at a position
print(cart)

last = cart.pop()                   # remove & return the last item
first = cart.pop(0)                 # remove & return by index
cart.remove("pen")                  # remove the first matching value
print(last, first, cart)

del cart[0]                         # delete by index (or slice)
print(cart)
cart.clear()
print(cart)
Output
['bag', 'pen', 'notebook', 'ruler', 'eraser']
eraser bag ['notebook', 'ruler']
['ruler']
[]

append vs extend is a classic mix-up: cart.append(["a", "b"]) adds one item (a nested list), while extend adds each element. remove raises ValueError if the value isn't there, and pop on an empty list raises IndexError.

Combining lists creates new ones:

Python
a = [1, 2]
b = [3, 4]
print(a + b)
print(a * 3)
print([*a, 0, *b])     # unpacking into a new list
Output
[1, 2, 3, 4]
[1, 2, 1, 2, 1, 2]
[1, 2, 0, 3, 4]

Sorting#

There are two ways to sort, and the difference matters:

Python
nums = [42, 7, 19, 3]

new_list = sorted(nums)     # returns a NEW sorted list
print(new_list, nums)

nums.sort()                 # sorts IN PLACE, returns None
print(nums)

nums.sort(reverse=True)
print(nums)
Output
[3, 7, 19, 42] [42, 7, 19, 3]
[3, 7, 19, 42]
[42, 19, 7, 3]

The key argument tells Python what to sort by. It takes a function that's applied to each item:

Python
words = ["banana", "Apple", "cherry", "fig"]
print(sorted(words))                    # uppercase sorts before lowercase
print(sorted(words, key=str.lower))     # case-insensitive
print(sorted(words, key=len))           # by length

students = [("Ada", 92), ("Linus", 79), ("Grace", 88)]
print(sorted(students, key=lambda s: s[1], reverse=True))
Output
['Apple', 'banana', 'cherry', 'fig']
['Apple', 'banana', 'cherry', 'fig']
['fig', 'Apple', 'banana', 'cherry']
[('Ada', 92), ('Grace', 88), ('Linus', 79)]

(lambda s: s[1] is a tiny inline function — you'll meet lambdas properly in the intermediate section.) Python's sort is stable: items that compare equal keep their original order, which lets you sort by several criteria in steps.

Other useful operations#

Python
nums = [3, 1, 4, 1, 5, 9, 2, 6]
print(len(nums), sum(nums), min(nums), max(nums))
print(nums.count(1))
nums.reverse()
print(nums)
Output
8 31 1 9
2
[6, 2, 9, 5, 1, 4, 1, 3]

Unpacking#

Assign list items to separate names in one go. A starred name collects "the rest":

Python
point = [3, 4]
x, y = point
print(x, y)

first, *middle, last = [10, 20, 30, 40, 50]
print(first, middle, last)
Output
3 4
10 [20, 30, 40] 50

Copying: references vs copies#

Assignment never copies a list — it creates another name for the same object. To get an independent list, make a copy:

Python
original = [1, 2, 3]
alias = original          # same list
copy1 = original.copy()   # new list
copy2 = original[:]       # new list (full slice)
copy3 = list(original)    # new list

alias.append(99)
print(original)
print(copy1, copy2, copy3)
Output
[1, 2, 3, 99]
[1, 2, 3] [1, 2, 3] [1, 2, 3]

These are shallow copies: the new list holds references to the same inner objects. For nested lists, use copy.deepcopy:

Python
import copy

grid = [[0, 0], [0, 0]]
shallow = grid.copy()
deep = copy.deepcopy(grid)

grid[0][0] = 1
print(shallow)   # inner lists are shared!
print(deep)
Output
[[1, 0], [0, 0]]
[[0, 0], [0, 0]]

The [[0] * n] * n trap

Python
bad = [[0] * 3] * 3             # three references to ONE inner list
bad[0][0] = 1
print(bad)

good = [[0] * 3 for _ in range(3)]   # three separate lists
good[0][0] = 1
print(good)
Output
[[1, 0, 0], [1, 0, 0], [1, 0, 0]]
[[1, 0, 0], [0, 0, 0], [0, 0, 0]]

Lists as stacks and queues#

A list makes an excellent stack (last in, first out) with append and pop. For a queue (first in, first out), pop(0) is slow on big lists because every item shifts — use collections.deque instead:

Python
from collections import deque

stack = []
stack.append("page1")
stack.append("page2")
print(stack.pop())          # back button: most recent first

queue = deque(["job1", "job2"])
queue.append("job3")
print(queue.popleft())      # first come, first served
Output
page2
job1

Worked example: a grade report#

Python
scores = [72, 95, 88, 61, 79, 95, 54]

passed = [s for s in scores if s >= 60]     # a list comprehension (more later!)
average = sum(scores) / len(scores)
top_three = sorted(scores, reverse=True)[:3]

print(f"Average: {average:.1f}")
print(f"Passed: {len(passed)}/{len(scores)}")
print(f"Top three: {top_three}")
print(f"Highest scorer count: {scores.count(max(scores))}")
Output
Average: 77.7
Passed: 6/7
Top three: [95, 95, 88]
Highest scorer count: 2

Common mistakes#

  • nums = nums.sort() — sort() returns None. Use nums.sort() or nums = sorted(nums).
  • Removing while iterating — build a new list instead: nums = [n for n in nums if n >= 0].
  • Confusing append and extend.
  • Assuming b = a copies — it doesn't.
  • Using a list for membership tests on large data — x in big_list scans every item. Sets (next lesson) do it instantly.

What's next#

Lists are flexible, but sometimes you want data that can't change, or a collection with no duplicates. Next up: tuples and sets.

Check your understanding

Quick quiz

0/3 answered
  1. 1.What is the difference between nums.sort() and sorted(nums)?

  2. 2.What does [1, 2] * 3 produce?

  3. 3.After a = [1, 2, 3] and b = a[:], what does b.append(4) do to a?

Finished reading?

Mark this lesson complete to track your progress.