I started this session with a challenge.
"Jose," I said, "print the names of all 40 students in this dataset - one per line."
He looked at me. Then at his keyboard. Then started typing print("Amina").
I let him get to the third name before I stopped him.
"What if there were 10,000 students?"
Silence.
"What if the list changed every week?"
More silence.
That's the setup for loops. You don't teach loops by explaining them - you first make people feel the pain of not having them. Then the solution lands differently.
The for Loop: Working Through a List
The for loop is Python's way of saying: go through every item in this collection and do something with each one.
My analogy: a class register. The teacher calls each name in order, marks attendance, moves to the next. They don't skip anyone. They don't stop early. They go through the whole list.
students = ["Amina", "Brian", "Njeri", "Kamau", "Wanjiku"]
for student in students:
print(f"Good morning, {student}! 👋")
Good morning, Amina! 👋
Good morning, Brian! 👋
Good morning, Njeri! 👋
Good morning, Kamau! 👋
Good morning, Wanjiku! 👋
Five names. One loop. If the list had 10,000 names, same code - still works.
Jose closed his half-written print() statements and deleted them. That reaction is why I love teaching this session.
range(): Counting Without a List
Sometimes you don't have a list of items - you just want to repeat something a specific number of times. That's what range() is for.
for i in range(5):
print(f"Attempt {i + 1}")
Attempt 1
Attempt 2
Attempt 3
Attempt 4
Attempt 5
Then came the question I wait for every cohort.
"Why does range(5) go from 0 to 4? Why not 1 to 5?"
Because Python counts like a programmer - starting from zero. range(5) means "give me 5 numbers starting at 0" - so 0, 1, 2, 3, 4.
If you want 1 to 5, you tell it explicitly:
for i in range(1, 6):
print(i)
1
2
3
4
5
You can even count in steps:
# Count in 10s - like a matatu filling up every 10km
for km in range(0, 51, 10):
print(f"Distance covered: {km} km")
Distance covered: 0 km
Distance covered: 10 km
Distance covered: 20 km
Distance covered: 30 km
Distance covered: 40 km
Distance covered: 50 km
Doing Real Work Inside a Loop
A loop is only useful if you do something meaningful inside it. We levelled up from printing names to processing data:
scores = [78, 45, 92, 61, 55, 88, 34, 73]
total = 0
for score in scores:
total = total + score
average = total / len(scores)
print(f"Class average: {average:.1f}")
Class average: 65.8
Then we added a conditional inside the loop - finding students who failed:
scores = [78, 45, 92, 61, 55, 88, 34, 73]
print("Students who need support:")
for i in range(len(scores)):
if scores[i] < 50:
print(f" Student {i + 1}: scored {scores[i]} - below pass mark")
Students who need support:
Student 2: scored 45 - below pass mark
Student 7: scored 34 - below pass mark
This is where students started to see it. A loop plus a conditional is already a mini data pipeline. You're iterating through records, applying a rule, flagging what matters.
The while Loop: Keep Going Until Something Changes
The for loop goes through a fixed collection. The while loop is different - it keeps running as long as a condition is true, and you don't always know in advance how many times that will be.
My analogy: a matatu waiting at the stage. It doesn't leave after a fixed number of passengers - it waits until it's full. While there's space, keep accepting passengers.
passengers = 0
capacity = 14
while passengers < capacity:
passengers += 1
print(f"Passenger {passengers} boards. Seats remaining: {capacity - passengers}")
print("Matatu is full. Twende!")
Passenger 1 boards. Seats remaining: 13
Passenger 2 boards. Seats remaining: 12
...
Passenger 14 boards. Seats remaining: 0
Matatu is full. Twende!
A more practical use - a simple login system that keeps asking until you get it right:
password = "lux2024"
attempts = 0
while True:
entry = input("Enter password: ")
attempts += 1
if entry == password:
print(f"✅ Access granted after {attempts} attempt(s).")
break
else:
print("❌ Wrong password. Try again.")
Enter password: wrongpass
❌ Wrong password. Try again.
Enter password: lux2024
✅ Access granted after 2 attempt(s).
The Infinite Loop Nobody Saw Coming
This was the moment of the session.
One student - Aisha - was building the login checker and forgot the break. Her loop just kept asking for the password. Forever. Her laptop stopped responding to anything else.
"How do I stop it?!"
Ctrl + C. Always Ctrl + C.
She pressed it. The program stopped. The room exhaled.
I told everyone to write Ctrl + C at the top of their notes and circle it. It's the emergency exit for every infinite loop - and you will need it at some point. Better to learn it when Aisha accidentally teaches you than when you're alone at midnight wondering why your computer is hot.
The lesson from Aisha's loop: every while True must have a break inside it. Without a way out, the loop runs until you force-quit the program or your laptop gives up.
break and continue: Taking Control of the Loop
Once students understood that loops run to completion, I showed them two ways to interrupt that:
break - stop the loop entirely and exit:
# Search for a student in the register
register = ["Amina", "Brian", "Njeri", "Kamau", "Wanjiku"]
target = "Njeri"
for student in register:
if student == target:
print(f"Found {target}! ✅")
break # No need to keep searching
print(f"Checking {student}...")
Checking Amina...
Checking Brian...
Found Njeri! ✅
continue - skip this item and move to the next one:
# Print all scores, but skip anyone who was absent (score = 0)
scores = [78, 0, 92, 0, 55, 88]
for score in scores:
if score == 0:
continue # Skip absent students
print(f"Score: {score}")
Score: 78
Score: 92
Score: 55
Score: 88
The analogy that landed for continue: a teacher calling the register and the student is absent. You don't stop the whole class - you just say "absent" and move to the next name.
Nested Loops: A Loop Inside a Loop
I saved this for the end - the concept that always gets a dramatic reaction.
# Multiplication table (3x3 preview)
for i in range(1, 4):
for j in range(1, 4):
print(f"{i} x {j} = {i * j}")
print("---")
1 x 1 = 1
1 x 2 = 2
1 x 3 = 3
---
2 x 1 = 2
2 x 2 = 4
2 x 3 = 6
---
3 x 1 = 3
3 x 2 = 6
3 x 3 = 9
---
"The outer loop runs - and every time it does, the inner loop runs all the way through."
You could see people mentally tracing the logic. I gave them a minute to sit with it before moving on. Some concepts need a moment, not a faster explanation.
A practical example - checking every student against every subject:
students = ["Amina", "Brian", "Njeri"]
subjects = ["Maths", "English", "Science"]
for student in students:
for subject in subjects:
print(f"{student} → {subject}")
print()
Amina → Maths
Amina → English
Amina → Science
Brian → Maths
Brian → English
Brian → Science
Njeri → Maths
Njeri → English
Njeri → Science
Practice Problems
Easy:
# 1. Print numbers 1 to 20 using a for loop and range()
# 2. Print only even numbers between 1 and 30
# 3. Loop through this list and print each item in uppercase:
# groceries = ["unga", "sukari", "mafuta", "chumvi"]
Medium:
# A simple ATM PIN checker - give the user 3 attempts
correct_pin = "4821"
attempts = 0
max_attempts = 3
while attempts < max_attempts:
pin = input("Enter your PIN: ")
attempts += 1
if pin == correct_pin:
print("PIN accepted. Welcome.")
break
else:
remaining = max_attempts - attempts
if remaining > 0:
print(f"Wrong PIN. {remaining} attempt(s) left.")
else:
print("Account locked. Please visit your branch.")
Challenge:
# Sales summary - loop through a list of daily sales,
# calculate total, find the highest day, count days below target
daily_sales = [12400, 8750, 15200, 6300, 19800, 11050, 9400]
target = 10000
# Your code here:
# 1. Total sales for the week
# 2. Best day (highest sales)
# 3. How many days missed the target
What I Noticed Teaching This Session
1. The pain-first setup works every time. Making Jose start writing 40 print() statements - even for just 3 names - made the loop feel like a rescue, not a concept.
2. Aisha's infinite loop was the best teaching moment of the week. An accident in front of the class, handled calmly, teaches Ctrl + C and loop safety more effectively than any slide ever could. I didn't plan it. I didn't need to.
3. Students started thinking like data people. When we looped through scores and flagged students below 50, someone said: "This is basically filtering - like SQL WHERE." That connection was electric. That's exactly what it is.
4. break and continue need contrast to make sense. Showing them without break (loop continues past the found item) before showing with break made the difference immediately visible.
What's Coming in Week 4: Functions
Right now our programs do things — but they can't remember how to do them. If we need to calculate a grade three times in different places, we write the logic three times. That's wrong.
Functions fix this:
def calculate_grade(score):
if score >= 80:
return "A"
elif score >= 70:
return "B"
elif score >= 60:
return "C"
elif score >= 50:
return "D"
else:
return "F"
print(calculate_grade(85)) # A
print(calculate_grade(62)) # C
print(calculate_grade(41)) # F
Write it once. Use it anywhere. That's next week.
Try It Yourself
- Download Python 3
- Download VS Code
- This week's code on GitHub ← link coming soon
Start with the ATM PIN checker - it combines everything from Week 2 (conditionals) and Week 3 (while loops). If that runs cleanly, you're ready for functions.
I'm a data trainer in Nairobi running a full data programme -
Python foundations → Data Science or Data Engineering specialisations.
I write weekly about what we covered, what worked, and what surprised me.
Follow along or drop your questions in the comments.

Top comments (0)