Lesson 9 — Ordered Collections

Lists

The Python list is the most versatile built-in collection — ordered, mutable, dynamically sized, and holding any mix of types. Mastering lists and their comprehensions is foundational to writing Pythonic code.

PYTHON — List basics
# Creation:
marks   = [65, 72, 80, 58, 91]
names   = ["Thandi", "Sipho", "Lerato"]
mixed   = [1, "two", 3.0, True, None]  # any types
empty   = []

# Access — zero-indexed:
print(marks[0])    # 65  — first
print(marks[-1])   # 91  — last
print(marks[-2])   # 58  — second from end
print(len(marks))  # 5
PYTHON — Slicing
# Slicing — [start:stop:step] — stop is exclusive:
print(marks[1:4])    # [72, 80, 58]   — indexes 1,2,3
print(marks[:3])     # [65, 72, 80]   — first 3
print(marks[2:])     # [80, 58, 91]   — from index 2
print(marks[::2])    # [65, 80, 91]   — every 2nd
print(marks[::-1])   # [91, 58, 80, 72, 65] — reversed copy

# Slicing creates a NEW list:
slice_copy = marks[1:3]
slice_copy[0] = 999
print(marks)   # unchanged
PYTHON — List methods
marks = [65, 72, 80, 58, 91]

# Mutating methods:
marks.append(77)          # add to end: [..., 77]
marks.insert(0, 50)       # insert at index 0: [50, 65, ...]
marks.remove(58)          # remove first occurrence of 58
popped = marks.pop()      # remove and return last: 77
popped2 = marks.pop(1)    # remove and return index 1
marks.sort()              # sort in place (returns None!)
marks.reverse()           # reverse in place
marks.extend([88, 95])    # add multiple elements

print(sorted(marks))      # sorted() returns NEW sorted list
print(marks)              # original unchanged by sorted()

List Comprehensions

List comprehensions are one of Python's most loved features — they create a new list from an iterable using a concise, readable expression.

PYTHON — List comprehensions
marks = [65, 72, 80, 58, 91, 44, 77]

# Basic comprehension:
squares   = [m ** 2 for m in marks]

# With filter:
passing   = [m for m in marks if m >= 50]

# Transformation and filter:
labels    = [f"{m}% — Pass" if m >= 50 else f"{m}% — Fail"
             for m in marks]

# Nested comprehension (flatten a 2D list):
matrix    = [[1,2,3],[4,5,6],[7,8,9]]
flat      = [n for row in matrix for n in row]
print(flat)  # [1, 2, 3, 4, 5, 6, 7, 8, 9]

# Comparing styles:
passing_loop = []
for m in marks:
    if m >= 50:
        passing_loop.append(m)

passing_comp = [m for m in marks if m >= 50]  # same result, cleaner

print(passing_comp)

Practice Task

Your Turn

Create a list of 8 learner marks. Write: (1) a comprehension for marks above average, (2) a comprehension that converts each mark to a grade label string, (3) sort the list in both ascending and descending order (without changing the original), (4) use slicing to get the top 3 marks, (5) use zip() to combine a names list and marks list into a list of tuples.

Common Mistakes

  • list.sort() returns None — never write sorted_marks = marks.sort(). Use sorted(marks) for a new sorted copy.
  • Slicing creates a shallow copy — modifying sliced sub-lists still affects nested mutable objects.
  • list.remove() removes only the first occurrence — loop if you need to remove all.
  • Modifying a list during iteration — always iterate a copy or use a comprehension.

Professional Tip

List comprehensions are Pythonic — they are not just shorthand but a signal that you understand the Python way. Learn to recognise when a comprehension is cleaner than a loop.

Mini Quiz

What does marks[::-1] return?