PYTHON PROGRAMMING • REVISION GUIDE

🐍 Python Lists

A practical guide to understanding, using, debugging, and reasoning about Python lists.

Don't just memorize list syntax. Learn to recognize the problem a list solves, predict what your code will do, explain why it works, and debug it when it doesn't.

1. The Big Picture: Why Do Lists Exist?

Start with the problem

Suppose you need to store five test scores.

score1 = 85
score2 = 92
score3 = 78
score4 = 91
score5 = 88

This works, but what happens when there are 500 scores? What if you need to calculate an average? Find the highest score? Process every score?

You need a way to store many related values under one variable name.

The solution: a list
scores = [85, 92, 78, 91, 88]

Now one variable represents the entire collection.

Think before coding

Which is easier to process with a loop?

score1 = 85
score2 = 92
score3 = 78
score4 = 91
score5 = 88

or:

scores = [85, 92, 78, 91, 88]

The important idea is not the brackets. The important idea is collection + repetition.

2. What Is a Python List?

numbers = [10, 20, 30, 40]

A Python list is an ordered collection of objects.

Characteristic What it means Example
Ordered Items have a defined position. [10, 20, 30]
Mutable Items can be changed after the list is created. numbers[0] = 100
Allows duplicates The same value can appear multiple times. [3, 3, 5]
Heterogeneous A list can contain different object types. [10, "Python", 3.5]
Dynamic Items can be added and removed. append()
Nestable A list can contain other lists. [[1,2], [3,4]]

Critical Thinking

Why might a list be better than five separate variables even when the number of values is small?

Think about what happens when you want to:

  • repeat an operation
  • count values
  • find a maximum
  • filter values
  • calculate statistics

3. Creating Lists

Empty list

numbers = []

List of numbers

scores = [85, 92, 78, 91]

List of strings

names = ["Ali", "Sara", "John"]

Mixed data types

student = ["Ali", 21, 3.8, True]

Nested list

matrix = [
    [1, 2],
    [3, 4],
    [5, 6]
]

Predict

What is the length of each list?

a = []
b = [10]
c = [10, 20, 30]
d = [[1, 2], [3, 4]]

Remember: len() counts the items directly contained in the list.

4. Accessing List Items

A list may contain many values. How do we retrieve one specific value?

Python solves this using indexing.

names = ["Ali", "Sara", "John", "Maria"]

Zero-based indexing

Index 0 1 2 3
Value Ali Sara John Maria
print(names[0])    # Ali
print(names[2])    # John

Common mistake

Students often think the first item is index 1.

names[1]

This gives Sara, not Ali.

The index represents the item's position starting from zero.

Negative indexing

print(names[-1])   # Maria
print(names[-2])   # John

Negative indexes count from the end.

Slicing

numbers = [10, 20, 30, 40, 50]

print(numbers[1:4])
[20, 30, 40]

The start index is included; the stop index is excluded.

Predict before running

numbers = [10, 20, 30, 40, 50]

print(numbers[0])
print(numbers[3])
print(numbers[-1])
print(numbers[1:4])
print(numbers[:3])
print(numbers[2:])

Write down the output before running the program. Then check your prediction.

5. Modifying Lists

We can retrieve an item with an index. But what if the value is wrong and needs to be changed?

Change one item

numbers = [10, 20, 30, 40]

numbers[1] = 200

print(numbers)
[10, 200, 30, 40]

Change every occurrence

If the same value appears multiple times, changing one index only changes one item.

numbers = [1, 3, 5, 3, 7, 3]

numbers[1] = 300

print(numbers)
[1, 300, 5, 3, 7, 3]

If the goal is to replace every 3, you need repetition.

numbers = [1, 3, 5, 3, 7, 3]

for i in range(len(numbers)):
    if numbers[i] == 3:
        numbers[i] = 300

print(numbers)
[1, 300, 5, 300, 7, 300]

The important distinction

Ask yourself:

  • Am I changing one known position?
  • Am I changing every item that meets a condition?

The first problem needs indexing. The second problem needs repetition + a condition.

6. Adding and Removing Items

append()

Use append() when you want to add one item to the end.

fruits = ["apple", "banana"]

fruits.append("mango")

print(fruits)
['apple', 'banana', 'mango']

insert()

fruits.insert(1, "orange")

Insert adds an item at a specific position.

remove()

fruits.remove("banana")

Removes the first matching value.

pop()

last_item = fruits.pop()

Removes and returns an item.

del

del fruits[1]

Deletes an item using its index.

Operation Use it when...
append() You want to add one item to the end.
insert() You want to add an item at a particular position.
remove() You know the value you want to remove.
pop() You want to remove an item and possibly use the removed value.
del You want to delete using an index.

Common Error: confusing remove() and pop()

numbers.remove(2)

This means: remove the value 2.

numbers.pop(2)

This means: remove the item at index 2.

7. Useful Built-in Functions

scores = [85, 92, 78, 91, 88]

print(len(scores))
print(sum(scores))
print(max(scores))
print(min(scores))
print(sorted(scores))
Function Purpose
len() Number of items
sum() Total of numeric items
max() Largest item
min() Smallest item
sorted() Returns a new sorted list

Error-driven learning: "int object is not callable"

Suppose you write:

sum = 100

print(sum(scores))

You may see:

TypeError: 'int' object is not callable

Why?

You accidentally used the name sum for a variable. Python can no longer access the built-in sum() function through that name.

Avoid variable names such as:

sum
list
str
int
len
max
min

8. Lists + for Loops

The problem

You have a list containing 1,000 values. You want to perform the same operation on every value. Writing 1,000 statements is not realistic.

A loop lets the program repeat the operation.

Loop directly through values

names = ["Ali", "Sara", "John"]

for name in names:
    print(name)

Use this approach when you care about the values.

Process every number

numbers = [3, 7, 10, 12]

for number in numbers:
    print(number ** 2)

Counting with a loop

scores = [85, 62, 91, 48, 77, 55, 93]

count = 0

for score in scores:
    if score >= 70:
        count += 1

print(count)

Recognize the pattern

Many list problems follow this structure:

for item in list:
    if condition:
        do_something()

This is the basic pattern behind:

  • counting
  • filtering
  • searching
  • calculating totals
  • building new lists

9. Index + Loop: When Position Matters

Sometimes you don't just need the value. You need to know where the value is.

Example: names and scores

names = ["Ali", "Sara", "John", "Maria"]
scores = [85, 92, 78, 88]

for i in range(len(names)):
    print(names[i], "->", scores[i])
Ali -> 85 Sara -> 92 John -> 78 Maria -> 88

Here, the same index connects the two lists.

Index names scores
0 Ali 85
1 Sara 92
2 John 78
3 Maria 88

Important question

Why not simply write:

for name in names:
    for score in scores:
        print(name, score)

Because the inner loop creates every possible combination. It does not preserve the one-to-one relationship between the two lists.

10. Nested Lists

What if one list is not enough to represent the structure of your data?

Consider a spreadsheet:

1  2
3  4
5  6

A natural Python representation is:

matrix = [
    [1, 2],
    [3, 4],
    [5, 6]
]

This is a list containing lists.

Accessing nested items

print(matrix[0][0])  # 1
print(matrix[1][1])  # 4
print(matrix[2][0])  # 5

Think of it as:

matrix[row][column]

Nested loops

for i in range(len(matrix)):
    for j in range(len(matrix[i])):
        print(matrix[i][j])

Trace the loop

For this matrix:

matrix = [
    [1, 2],
    [3, 4],
    [5, 6]
]

Ask:

  • What is the first value of i?
  • What is the first value of j?
  • What does matrix[i][j] become?
  • When does the inner loop finish?
  • When does i change?

Row totals

matrix = [
    [3, 8, 2],
    [10, 5, 7],
    [4, 12, 6]
]

for row in matrix:
    total = 0

    for number in row:
        total += number

    print(total)
13 22 22

Notice that we did not need indexes here.

When you only need the values, looping directly through the values is often simpler.

11. List Comprehensions

Why do we need them?

Suppose you want to create a new list by transforming every item in another list.

The normal loop is:

numbers = [1, 2, 3, 4, 5]

squares = []

for number in numbers:
    squares.append(number ** 2)

Python provides a compact way to express the same pattern.

squares = [number ** 2 for number in numbers]

The basic pattern

[expression for item in iterable]

Read it conceptually as:

"For each item, calculate this expression and put the result into a new list."

Transformation

numbers = [1, 2, 3, 4]

doubled = [n * 2 for n in numbers]
[2, 4, 6, 8]

Filtering

numbers = [3, 15, 8, 22, 4, 30]

large = [n for n in numbers if n > 10]
[15, 22, 30]

Do not memorize the syntax blindly

Start with the normal loop:

result = []

for n in numbers:
    if n > 10:
        result.append(n)

Then identify:

  • What am I putting into the new list?
  • Where does each item come from?
  • Which items should be included?

Then translate it into:

[n for n in numbers if n > 10]

Flattening a nested list

matrix = [
    [1, 2],
    [3, 4],
    [5, 6]
]

flat = [number for row in matrix for number in row]

print(flat)
[1, 2, 3, 4, 5, 6]

Read nested comprehensions carefully

[number for row in matrix for number in row]

A good strategy is to expand it back into ordinary loops when you are unsure:

result = []

for row in matrix:
    for number in row:
        result.append(number)

If you cannot explain the ordinary loop, you probably should not write the comprehension yet.

12. Debugging Lists

A strong programmer does not try to avoid every error. A strong programmer learns how to read and investigate errors.

Error 1: Index out of range

numbers = [10, 20, 30]

print(numbers[3])

There is no index 3. The valid indexes are:

0, 1, 2

The list has length 3, but its last index is 2.

Error 2: Modifying while looping incorrectly

Changing the size of a list while iterating over it can create unexpected behavior.

For example, repeatedly removing items from the same list while moving through it requires careful reasoning.

When possible, consider creating a new list instead.

Error 3: Using parentheses instead of brackets

numbers = (10, 20, 30)

This creates a tuple, not a list.

numbers = [10, 20, 30]

This creates a list.

Error 4: Calling a list like a function

numbers = [10, 20, 30]

print(numbers(0))

A list is indexed with square brackets:

print(numbers[0])

Error 5: Forgetting that indexing starts at zero

names = ["Ali", "Sara", "John"]

print(names[1])

The result is "Sara", not "Ali".

13. Practice: From Basic to Advanced

Level 1 — Basic

  1. Create a list of five favorite foods.
  2. Print the first item.
  3. Print the last item.
  4. Change the third item.
  5. Add a new item.
  6. Remove one item.
  7. Print the length.

Level 2 — Lists + Loops

  1. Print every item in a list.
  2. Print the square of every number.
  3. Count numbers greater than 50.
  4. Calculate the sum of all numbers.
  5. Build a list containing only even numbers.

Level 3 — Indexing

  1. Print names and scores side by side.
  2. Find the index of the highest score.
  3. Compare two lists item by item.
  4. Replace every occurrence of a value.

Level 4 — Nested Lists

  1. Access a specific matrix item.
  2. Print every matrix item.
  3. Calculate each row's total.
  4. Find the maximum value in each row.

Level 5 — List Comprehensions

  1. Convert a loop into a comprehension.
  2. Filter numbers using a comprehension.
  3. Convert temperatures using a comprehension.
  4. Flatten a nested list.

14. Critical Thinking Questions

1. When should you loop directly through values instead of using indexes?
2. When does an index become necessary?
3. Why does range(len(numbers)) produce useful indexes?
4. What is the difference between modifying a list and creating a new list?
5. Why is a nested loop necessary for a matrix?
6. What problem does a list comprehension solve?
7. When might a normal loop be clearer than a list comprehension?
8. If two lists contain related information, what assumptions must be true before matching them by index?
9. What happens if the two lists have different lengths?
10. If your code produces the correct output but you cannot explain why it works, have you really mastered the concept?

15. Code Tracing Practice

Trace 1

numbers = [2, 4, 6]

total = 0

for n in numbers:
    total += n

print(total)

Before running it, write down the value of total after each loop iteration.

Trace 2

numbers = [3, 8, 12, 5]

result = []

for n in numbers:
    if n > 7:
        result.append(n)

print(result)

Track the contents of result after every iteration.

Trace 3 — Nested Loop

matrix = [
    [1, 2],
    [3, 4]
]

for row in matrix:
    for number in row:
        print(number)

How many times does the inner loop execute?

16. Challenge Problems

Challenge 1 — Running Sum

numbers = [2, 4, 6, 8]

Create:

[2, 6, 12, 20]

Each item represents the total accumulated up to that point.

Challenge 2 — Sum Greater Elements

numbers = [5, 12, 3, 20, 7, 15]

Calculate the sum of values greater than 10.

Challenge 3 — Common Unique Items

list1 = [1, 2, 3, 4, 5]
list2 = [3, 4, 4, 5, 6, 7]

Create a list containing values found in both lists without duplicates.

Expected:

[3, 4, 5]

Challenge 4 — Index-wise Combination

list1 = [1, 2, 3, 4]
list2 = [10, 20, 30, 40]

Create:

[11, 22, 33, 44]

Do it using indexes. Do not use zip().

Challenge 5 — Product of Digits

numbers = [123, 45, 67]

Produce:

[6, 20, 42]

Because:

123 → 1 × 2 × 3 = 6
45  → 4 × 5 = 20
67  → 6 × 7 = 42

17. 🏆 Final Challenge — Student Grade Analyzer

You are given two related lists:

students = ["Ali", "Sara", "John", "Maria", "David"]

scores = [85, 92, 67, 74, 58]

Build a program that analyzes the students' scores.

Display every student and score.
Calculate the number of students.
Count passing students.
Count failing students.
Calculate the average score.
Find the highest score.
Find the student who earned the highest score.
Create a list containing only passing students.
Assign each student a letter grade.

Do not start coding immediately.

First identify:

  • What information do I have?
  • What information do I need to calculate?
  • Which tasks require a loop?
  • Which tasks require an index?
  • Which tasks require a new list?
  • Which tasks can use a built-in function?

This is the transition from writing syntax to designing an algorithm.

18. How to Approach an Unfamiliar List Problem

Ask these questions in order:

  1. What is my input?
    Is it one list? Two lists? A nested list?
  2. What should my output look like?
    One value? A count? A new list? Multiple values?
  3. Do I need every item?
    If yes, consider a loop.
  4. Do I need the position?
    If yes, consider an index.
  5. Am I selecting some items?
    You probably need a condition.
  6. Am I creating a new collection?
    Consider building a new list.
  7. Is the data nested?
    You may need a nested loop.
  8. Can I clearly express the logic?
    Write the ordinary loop first.
  9. Can I simplify it?
    Only after the logic works, consider a list comprehension.

19. Python Lists — Quick Reference

Task Syntax
Create numbers = [1, 2, 3]
Empty list numbers = []
Access numbers[0]
Last item numbers[-1]
Slice numbers[1:4]
Length len(numbers)
Change numbers[0] = 100
Add to end numbers.append(100)
Insert numbers.insert(1, 100)
Remove value numbers.remove(100)
Remove by index numbers.pop(1)
Delete by index del numbers[1]
Total sum(numbers)
Largest max(numbers)
Smallest min(numbers)
Sorted copy sorted(numbers)
Loop through values for n in numbers:
Loop through indexes for i in range(len(numbers)):
Comprehension [expression for item in numbers]
Filter comprehension [item for item in numbers if condition]

20. 🧠 Mastery Check

Before moving on from lists, you should be able to explain these without looking at your notes:

  • □ What problem does a list solve?
  • □ What does it mean for a list to be mutable?
  • □ Why does Python use zero-based indexing?
  • □ How do you access the last item?
  • □ What is the difference between an index and a value?
  • □ How do you change one item?
  • □ How do you change every item that meets a condition?
  • □ What is the difference between remove() and pop()?
  • □ When should you loop directly through values?
  • □ When do you need indexes?
  • □ Why are nested loops useful with nested lists?
  • □ What problem does a list comprehension solve?
  • □ How do you convert a normal loop into a comprehension?
  • □ How do you debug an IndexError?
  • □ How can you determine what your code is doing without running it?
  • □ Can you explain your algorithm before writing the code?

Final principle

Don't memorize 20 list tricks. Learn to recognize the underlying patterns.

Most list problems reduce to a small number of ideas:

Access

Get one item.

numbers[i]
Traversal

Visit every item.

for n in numbers
Selection

Keep items that meet a condition.

if condition
Transformation

Turn each item into something new.

n * 2
Accumulation

Combine values into a result.

total += n
Indexing

Work with position.

range(len(...))
Nesting

Process collections inside collections.

for row ... for item ...
Construction

Build a new list.

result.append(...)

🎫 Exit Ticket

1. Explain

In your own words, what problem do Python lists solve?

2. Predict

numbers = [10, 20, 30, 40]

print(numbers[-2])

What will be printed?

3. Debug

numbers = [10, 20, 30]

print(numbers[3])

What error occurs and why?

4. Choose

When would you use:

  • a direct for loop?
  • an indexed for loop?
  • a nested loop?
  • a list comprehension?

5. Transfer

Think of something outside programming that could be represented as a list. Explain why a list is an appropriate representation.

Reference

For formal Python documentation, see the Python documentation on data structures and lists.

This revision guide is designed as instructional material rather than a replacement for the official Python documentation.