In the previous lesson, you learned how Python makes decisions with if, elif, and match. Now let's teach your code to repeat itself — intelligently.
Imagine you have a basket of apples. You need to check each one. Do you pick them up one by one, or all at once?
That's the power of loops. They let you repeat tasks without repeating code. Today, you'll learn Python's three loop masters.
You'll automate tasks, process data, and write code that works while you sleep!
- Python
forloops — iterating lists, dictionaries, and usingenumerate() - Python
whileloops — and how to avoid the infinite-loop trap - The
range()function in all three of its forms - Loop control:
break,continue, and the rarely-taught loopelse - Nested loops for grids and multi-dimensional data
- A complete hands-on project: a Smart Inventory System
- 1. What Are Loops? Your Personal Code Repeater
- 2. Python For Loops: The Organized Counter
- 3. Python While Loops: The Persistent Guardian
- 4. Python Range: The Number Generator
- 5. Loop Control Statements: Break, Continue, and Else
- 6. Nested Loops: Loops Within Loops
- 7. Advanced Project: Smart Inventory System
- 8. Choosing the Right Loop: Quick Guide
- 9. Quick Reference Cheat Sheet
- 10. Common Pitfalls (And How to Avoid Them)
- 11. Practice Exercises
- 12. FAQ
- 13. Summary
🔁 1. What Are Loops? Your Personal Code Repeater
Loops are programming structures that repeat a block of code multiple times. Instead of writing the same instruction 100 times, you write it once and tell Python: "Do this 100 times."
Each item moves down the line. The same station performs the exact same action on every item. The loop is that station—consistent, reliable, and efficient.
🔂 2. Python For Loops: The Organized Counter
For loops are perfect when you know exactly how many times you want to repeat something. They work through items in a collection, one by one.
The Basic For Loop: Meeting Each Item
Let's greet every student in a class list.
students list one name at a time, temporarily storing each name in the loop variable student, and prints a greeting for every single one before moving on.
students = ["Alice", "Bob", "Charlie", "Diana"]
for student in students:
print(f"Hello, {student}! Welcome to class.")
Output:
Hello, Alice! Welcome to class.
Hello, Bob! Welcome to class.
Hello, Charlie! Welcome to class.
Hello, Diana! Welcome to class.
The loop took the list students and went through it item by item. The variable student changes each time—first "Alice", then "Bob", and so on.
You can name it anything:
for person in students:, for x in students:, for item in students:. Choose a name that makes sense for what you're looping through!
For Loops with Dictionaries: Keys and Values
Dictionaries store data in key-value pairs. You can loop through them in different ways.
.items(), which unpacks each entry into a key and value pair (name and grade) in one step.
student_grades = {"Alice": 95, "Bob": 87, "Charlie": 92}
print("Just keys:")
for name in student_grades:
print(f"Student: {name}")
print("\nKeys and values together:")
for name, grade in student_grades.items():
print(f"{name} scored {grade} marks.")
Output:
Just keys:
Student: Alice
Student: Bob
Student: Charlie
Keys and values together:
Alice scored 95 marks.
Bob scored 87 marks.
Charlie scored 92 marks.
The .items() method is magic—it gives you both the key and value in one clean step.
The Powerful enumerate() Function: Get the Position
What if you need the item AND its position in the list? Use enumerate().
fruits list in enumerate(), which hands back both a running position number (starting at 0) and the item itself on every pass — here index + 1 converts that to a human-friendly count starting at 1.
fruits = ["Apple", "Banana", "Cherry"]
for index, fruit in enumerate(fruits):
print(f"Fruit #{index + 1} is {fruit}")
Output:
Fruit #1 is Apple
Fruit #2 is Banana
Fruit #3 is Cherry
enumerate() adds a counter to your loop. The index + 1 makes it human-friendly (starting from 1 instead of 0).
If you're looping through a list and try to add or remove items inside the loop, Python can get confused. Instead, create a new list or loop through a copy.
⏳ 3. Python While Loops: The Persistent Guardian
While loops keep running as long as a condition remains true. They're perfect when you don't know how many repetitions you'll need.
The Basic While Loop: Keep Going While True
Imagine a countdown timer.
countdown still greater than 0?" — printing and decreasing it each pass — until the condition finally becomes False, at which point the loop ends and "Blast off!" prints.
countdown = 5
while countdown > 0:
print(f"Countdown: {countdown}")
countdown = countdown - 1 # This is crucial!
print("Blast off! 🚀")
Output:
Countdown: 5
Countdown: 4
Countdown: 3
Countdown: 2
Countdown: 1
Blast off! 🚀
The loop checks: "Is countdown greater than 0?" If yes, it runs the code block. The line countdown = countdown - 1 changes the value, moving us toward the end.
The Infinite Loop Trap (and How to Escape)
What happens if we forget to change the condition?
# symbols, countdown would never change, the condition would stay True forever, and your program would freeze printing "Stuck in loop!" endlessly.
# WARNING: This would run forever if uncommented!
# countdown = 5
# while countdown > 0:
# print("Stuck in loop!") # We never change countdown!
This is an infinite loop—a programmer's common mistake. Always ensure something in your loop changes the condition.
If you accidentally create an infinite loop, press Ctrl + C in your terminal. This sends an interrupt signal and stops the program immediately.
Real Example: User Input Validation
While loops are excellent for checking user input until it's correct.
age so the loop is guaranteed to run at least once, then keeps asking for input — validating it's all digits with .isdigit() — until a value between 0 and 120 is entered.
age = -1 # Start with an invalid age
while age < 0 or age > 120:
user_input = input("Please enter your age (0-120): ")
# First, check if it's a number
if user_input.isdigit():
age = int(user_input)
else:
print("That's not a valid number. Try again.")
print(f"Thank you! Your age is {age}.")
This loop will keep asking until the user enters a reasonable age. It combines condition checking with user interaction beautifully.
.isdigit() only accepts non-negative whole numbers as text — typing "-5" or "18.5" will fail the check and trigger "not a valid number," even though a human would call those "numbers" too. If you need to accept negative or decimal input, you'd validate with a try/except around int() or float() instead (covered in the previous lesson on type casting).
🔢 4. Python Range: The Number Generator
Range() is a special function that generates a sequence of numbers. It's the perfect partner for for loops when you need to repeat something a specific number of times.
Three Ways to Use Range
1. Simple Count: range(stop)
range(5) always starts at 0 and stops before 5.
for i in range(5):
print(f"Loop iteration #{i}")
Generates: 0, 1, 2, 3, 4 (5 numbers total, starting from 0)
2. Start and Stop: range(start, stop)
for i in range(3, 8):
print(i)
Generates: 3, 4, 5, 6, 7 (starts at 3, stops before 8)
3. With Step: range(start, stop, step)
for i in range(0, 10, 2):
print(i)
Generates: 0, 2, 4, 6, 8 (counts by 2s)
range(5) = 0 to 4range(2, 6) = 2 to 5range(1, 10, 3) = 1, 4, 7 (steps of 3)The stop number is never included in the sequence.
Range in Action: Multiplication Table Generator
Let's create a multiplication table for the number 7.
i from 1 through 10, multiplying it by 7 each time, and prints one formatted line of the times table per iteration.
multiplier = 7
print(f"Multiplication Table for {multiplier}:")
print("-" * 30)
for i in range(1, 11): # 1 through 10
result = multiplier * i
print(f"{multiplier} × {i} = {result}")
Output:
Multiplication Table for 7:
------------------------------
7 × 1 = 7
7 × 2 = 14
7 × 3 = 21
7 × 4 = 28
7 × 5 = 35
7 × 6 = 42
7 × 7 = 49
7 × 8 = 56
7 × 9 = 63
7 × 10 = 70
Clean, efficient, and adaptable—change the multiplier or range for any table!
🎮 5. Loop Control Statements: Break, Continue, and Else
Sometimes you need to change how loops behave mid-execution. Python gives you special commands for this.
Break: The Emergency Exit
Break immediately stops the loop, no matter what.
break exits the loop immediately, so numbers 43–100 are never checked.
secret_number = 42
for guess in range(1, 101):
if guess == secret_number:
print(f"Found it! The secret number is {guess}")
break # Stop looking immediately
print(f"Tried {guess}... not correct.")
Once we find 42, we don't need to check 43-100. Break saves us time.
Continue: The Skipper
Continue skips the rest of the current iteration and jumps to the next one.
0, continue immediately jumps to the next number — skipping the division line entirely — which is exactly what prevents a ZeroDivisionError.
numbers = [12, 0, 8, 3, 0, 7]
for num in numbers:
if num == 0:
print("Skipping zero - can't divide by it!")
continue # Skip to next number
result = 100 / num
print(f"100 ÷ {num} = {result:.2f}")
When we hit zero, we skip the division (which would cause an error) and move to the next number.
Loop Else: The Completion Reward
Yes, loops can have else blocks! They run only if the loop completes normally (without hitting a break).
break — which means the else block runs and reports failure.
passwords_to_try = ["123456", "password", "letmein"]
correct_password = "secret123"
for attempt in passwords_to_try:
if attempt == correct_password:
print("Access granted!")
break
else:
# This runs ONLY if the break was NOT hit
print("Access denied. All passwords failed.")
The else acts like a safety net—it tells us when we've exhausted all options without success.
Think of it as: "If the loop finished its job completely (no breaks), then do this extra step." It's perfect for search operations where "not found" is a valid outcome.
🧩 6. Nested Loops: Loops Within Loops
Sometimes you need to combine loops. This is common when working with grids, tables, or multi-dimensional data.
Creating a Pattern Grid
Let's make a simple coordinate grid.
print("Coordinate Grid:")
print(" 0 1 2 3 4") # Column headers
print(" - - - - -")
for row in range(5): # Outer loop: rows
print(f"{row}|", end=" ") # Row label
for col in range(5): # Inner loop: columns
print(f"{row},{col}", end=" ")
print() # New line after each row
Output:
Coordinate Grid:
0 1 2 3 4
- - - - -
0| 0,0 0,1 0,2 0,3 0,4
1| 1,0 1,1 1,2 1,3 1,4
2| 2,0 2,1 2,2 2,3 2,4
3| 3,0 3,1 3,2 3,3 3,4
4| 4,0 4,1 4,2 4,3 4,4
The outer loop handles rows. For each row, the inner loop handles all columns. This creates a 5×5 grid.
Each level of nesting multiplies complexity. Three nested loops (25×25×25) runs 15,625 times! Always ask: "Is there a simpler way?" Sometimes list comprehensions or built-in functions are better.
📦 7. Advanced Project: Smart Inventory System
Let's build a complete system that combines all loop concepts.
for loop to display every item, a for-inside-while combo to top up any item below 20 units, nested for loops to print 5 price labels per item, and a for...else search that reports whether any item is priced above $1.00.
# Smart Inventory System
inventory = {
"Apples": {"stock": 50, "price": 0.99},
"Bananas": {"stock": 30, "price": 0.49},
"Oranges": {"stock": 25, "price": 0.79},
"Milk": {"stock": 15, "price": 2.49}
}
# Task 1: Display inventory with FOR loop
print("📦 CURRENT INVENTORY")
print("=" * 40)
for item, details in inventory.items():
print(f"{item:10} | Stock: {details['stock']:3} | Price: ${details['price']:.2f}")
# Task 2: Restock low items with WHILE loop
print("\n🔄 RESTOCKING LOW ITEMS")
print("=" * 40)
low_threshold = 20
for item in list(inventory.keys()): # Use list() to avoid modification issues
while inventory[item]["stock"] < low_threshold:
print(f"{item} is low ({inventory[item]['stock']}). Adding 10 more...")
inventory[item]["stock"] += 10
# Task 3: Generate price labels with RANGE
print("\n🏷️ GENERATING PRICE LABELS")
print("=" * 40)
labels_needed = 5 # Labels per item
for item, details in inventory.items():
print(f"\nLabels for {item}:")
for label_num in range(1, labels_needed + 1):
print(f" Label #{label_num}: {item} - ${details['price']:.2f}")
# Task 4: Find expensive items with BREAK
print("\n💰 FINDING EXPENSIVE ITEMS")
print("=" * 40)
price_limit = 1.00
for item, details in inventory.items():
if details["price"] > price_limit:
print(f"{item} costs ${details['price']:.2f} (over ${price_limit})")
break # Stop after finding first expensive item
else:
print(f"No items over ${price_limit} found.")
print("\n✅ Inventory update complete!")
This project shows loops working together: for for organized iteration, while for conditional repetition, range for counting, and break/else for control.
:.2f — except the line (over ${price_limit}), which prints "over $1.0", not "$1.00", because that one spot is missing the :.2f format spec used everywhere else. Only Milk ($2.49) triggers Task 4's break, and only Milk (15 < 20) triggers a restock in Task 2 — worth confirming yourself by running it, since it's a great way to see loop logic and string formatting interact in a realistic script.
⚖️ 8. Choosing the Right Loop: Quick Guide
- Use
forwhen:- You're iterating over a known collection (list, string, dictionary).
- You know exactly how many iterations you need.
- You need to process each item in a sequence.
- Use
whilewhen:- You're waiting for a condition to change.
- You don't know how many iterations you'll need.
- You're monitoring something (user input, sensor data, game state).
- Use
range()withforwhen:- You need to repeat code a specific number of times.
- You need numerical sequences (for indexing, counting, etc.).
- You're working with numerical patterns.
Try rewriting
for loops as while loops and vice versa. This deepens your understanding of how both work. Most for loops can be written as while, but not always elegantly!
📚 9. Quick Reference Cheat Sheet
For loops:
for item in my_list: # iterate a list
pass
for key in my_dict: # iterate keys only
pass
for key, value in my_dict.items(): # iterate key + value
pass
for index, item in enumerate(my_list): # iterate with position
pass
While loops:
while condition:
pass # runs as long as condition is True
# something inside MUST eventually make condition False
Range:
range(5) # 0, 1, 2, 3, 4
range(2, 6) # 2, 3, 4, 5
range(1, 10, 3) # 1, 4, 7
Loop control:
break # exit the loop immediately
continue # skip to the next iteration
else: # (on a loop) runs only if break was NOT hit
🚧 10. Common Pitfalls (And How to Avoid Them)
# Bad — countdown never changes, this runs forever
countdown = 5
while countdown > 0:
print("Stuck!")
# Good — countdown moves toward 0 every pass
countdown = 5
while countdown > 0:
print(countdown)
countdown -= 1
❌ Pitfall 2: Modifying a list while looping over it directly
# Risky — removing items while iterating skips elements
for item in inventory:
del inventory[item] # can raise RuntimeError
# Safe — loop over a copy of the keys instead
for item in list(inventory.keys()):
del inventory[item]
❌ Pitfall 3: Confusing loop else with if else
# The 'else' here is NOT tied to an 'if' —
# it's tied to the 'for' loop itself
for attempt in passwords_to_try:
if attempt == correct_password:
break
else:
print("No match found") # runs only if 'break' never fired
❌ Pitfall 4: Inconsistent number formatting across a script
# Bad — inconsistent output: $2.49 vs $1.0
print(f"Price: ${price:.2f}")
print(f"Limit: ${price_limit}") # missing :.2f
# Good — format every price the same way
print(f"Price: ${price:.2f}")
print(f"Limit: ${price_limit:.2f}")
🏋️ 11. Practice Exercises
Using a
for loop and range(1, 101), print "Fizz" for multiples of 3, "Buzz" for multiples of 5, "FizzBuzz" for multiples of both, and the number otherwise.
Write a
while loop that keeps asking the user for numbers and adds them to a running total, stopping the moment they enter a negative number.
Use nested loops and
break to check whether a number is prime (hint: use the inner loop's else to confirm no divisor was found).
Given a dictionary of
{item: {"price": x, "quantity": y}}, use .items() in a for loop to calculate and print the total cost.
Take the Smart Inventory System project from this post and fix the
price_limit formatting gotcha so every dollar amount consistently shows 2 decimal places.
❓ 12. Frequently Asked Questions
What is the difference between a for loop and a while loop in Python?
A for loop iterates over a known collection (a list, string, dictionary, or range) a fixed number of times. A while loop keeps running as long as a condition stays True, which is ideal when you don't know in advance how many repetitions you'll need.
Does range() include the stop number?
No. range(start, stop) always stops before the stop value — range(1, 5) produces 1, 2, 3, 4, never 5.
What's the difference between break and continue?
break exits the entire loop immediately, skipping any remaining iterations. continue only skips the rest of the current iteration and moves on to the next one — the loop keeps running.
What does the else block on a for loop actually do?
It runs only if the loop completes all its iterations without ever hitting a break. It's commonly used in search patterns: if you find what you're looking for, you break; if the loop finishes naturally, the else reports "not found."
How do I avoid an infinite while loop?
Make sure something inside the loop body changes the variable being tested in the condition, moving it toward becoming False. If you do get stuck in one, press Ctrl+C in your terminal to force-stop the program.
Is it safe to remove items from a list while looping over it?
No — modifying a list's length while iterating over it directly can skip elements or raise errors. Loop over a copy instead, such as for item in list(my_dict.keys()):, as shown in the inventory project above.
📝 13. Summary: Your Loop Mastery Checklist ✅
You now command Python's repetition engines:
- For Loops: Your organized iterator for collections and sequences.
- While Loops: Your persistent guardian for uncertain repetition.
- Range: Your number generator for counting and sequencing.
- Loop Control: Break (exit), Continue (skip), and Else (completion).
- Nested Loops: For multi-dimensional processing.
Ready for the next step? Continue to Python Functions, where you'll wrap this repetition logic into clean, reusable blocks of code you can call whenever you need them.
Happy looping! 🔄✨
Comments
Post a Comment