Python for Loop Explained — Syntax, Examples and Common Mistakes
Every real program does repetitive work. A weather app checks temperatures for 365 days. A music app loads every song in your library. An online store applies a discount to every item in your cart. Without a way to repeat actions automatically, you'd have to write the same line of code hundreds of times — which is not just tedious, it's fragile. Change one thing and you'd have to update every single copy.
What a for Loop Actually Does — The Core Idea
A for loop says: 'take this collection of things, visit each one in order, and run the same block of code for each.' Python handles all the counting and moving-forward for you. You just describe what to DO on each visit.
The collection you loop over can be a list of names, a string of characters, a range of numbers — almost anything that holds multiple items. Python calls these 'iterables', but you can think of them as 'anything you can step through one piece at a time.'
The basic shape of a for loop is always the same: the word for, then a variable name you choose (this is your 'current item' holder), then in, then the collection, then a colon. Everything indented below that runs once per item. The indentation is not optional — Python uses it to know which lines belong inside the loop.
# A simple list of planet names planets = ["Mercury", "Venus", "Earth", "Mars", "Jupiter"] # for loop: visit each planet one at a time for planet in planets: # 'planet' holds the current item each round print(f"Visiting {planet}") # this line runs once per planet # This line is NOT indented, so it runs AFTER the loop finishes print("Tour of the solar system complete!")
Visiting Venus
Visiting Earth
Visiting Mars
Visiting Jupiter
Tour of the solar system complete!
Looping Over Numbers with range() — Your Most-Used Tool
Most beginners need to repeat something a set number of times — run a countdown from 10, process 100 items, print a multiplication table. For that, Python gives you range(). It generates a sequence of numbers on demand without storing them all in memory.
range(5) gives you 0, 1, 2, 3, 4 — five numbers starting at zero. This trips up almost every beginner: range counts from zero by default, and the number you pass in is NOT included. Think of it as 'up to but not including 5.'
range(start, stop) lets you control where counting begins. range(1, 6) gives 1, 2, 3, 4, 5. range(start, stop, step) adds a step — range(0, 10, 2) gives you every even number from 0 to 8. You can even count backwards with a negative step: range(5, 0, -1) counts down from 5 to 1.
# --- Example 1: Basic range, repeat 5 times --- print("=== Countdown prep ===") for step_number in range(5): # generates 0, 1, 2, 3, 4 print(f"Step {step_number}") # --- Example 2: range with start and stop --- print("\n=== Lap counter ===") for lap in range(1, 6): # generates 1, 2, 3, 4, 5 (NOT 6) print(f"Lap {lap} complete") # --- Example 3: range with a step (every 2nd number) --- print("\n=== Even floors only ===") for floor in range(0, 11, 2): # 0, 2, 4, 6, 8, 10 print(f"Elevator stops at floor {floor}") # --- Example 4: counting backwards --- print("\n=== Rocket launch ===") for countdown in range(5, 0, -1): # 5, 4, 3, 2, 1 print(f"T-minus {countdown}...") print("Liftoff!")
Step 0
Step 1
Step 2
Step 3
Step 4
=== Lap counter ===
Lap 1 complete
Lap 2 complete
Lap 3 complete
Lap 4 complete
Lap 5 complete
=== Even floors only ===
elevator stops at floor 0
Elevator stops at floor 2
Elevator stops at floor 4
Elevator stops at floor 6
Elevator stops at floor 8
Elevator stops at floor 10
=== Rocket launch ===
T-minus 5...
T-minus 4...
T-minus 3...
T-minus 2...
T-minus 1...
Liftoff!
Looping Over Strings, Dictionaries, and Using enumerate()
A string in Python is just a sequence of characters, and you can loop over it the same way you loop over a list. Python will hand you one character at a time. This is surprisingly useful for tasks like counting vowels, reversing text, or scanning for special characters.
Dictionaries are a bit different. When you loop over a dictionary directly, you get its keys. To get both keys and values together, use .items() — it hands you both as a pair each round.
Here's a power move: enumerate(). Often you need both the item AND its position number. Without enumerate, beginners create a separate counter variable and increment it manually — messy and error-prone. enumerate(collection) hands you a tuple of (index, item) on each pass. You unpack it by naming two variables after for.
# --- Looping over a string --- word = "Python" print("=== Characters in 'Python' ===") for character in word: # each character, one at a time print(character) # --- Looping over a dictionary --- student_grades = { "Alice": 92, "Bob": 78, "Carlos": 85 } print("\n=== Grade Report ===") for student_name, grade in student_grades.items(): # .items() gives key AND value if grade >= 90: remark = "Excellent" elif grade >= 80: remark = "Good" else: remark = "Keep practising" print(f"{student_name}: {grade} — {remark}") # --- Using enumerate() to track position --- race_finishers = ["Aisha", "Ben", "Clara", "David"] print("\n=== Race Results ===") for position, runner_name in enumerate(race_finishers, start=1): # start=1 so positions begin at 1 print(f"Position {position}: {runner_name}")
P
y
t
h
o
n
=== Grade Report ===
Alice: 92 — Excellent
Bob: 78 — Keep practising
Carlos: 85 — Good
=== Race Results ===
Position 1: Aisha
Position 2: Ben
Position 3: Clara
Position 4: David
Controlling the Loop — break, continue, and the else Clause
Sometimes you don't want to visit every single item. Maybe you're searching a list for a specific value and want to stop the moment you find it — no point checking the rest. That's break. It exits the loop immediately, as if you slammed a book shut.
continue is the opposite of a full stop — it's more of a skip. When Python hits continue, it abandons the current iteration and jumps straight to the next one. Useful when you want to process most items but ignore ones that fail a condition.
Python's for loop also has an else clause — and this genuinely surprises most people. The else block runs only if the loop completed normally, meaning it was NOT interrupted by a break. It's perfect for 'search and report' patterns: loop through items looking for something, break if found, and use else to handle the 'not found' case cleanly.
# --- break: stop the moment we find what we need --- passenger_list = ["Tom", "Sara", "Jake", "Mia", "Leo"] target_passenger = "Jake" print("=== Boarding check ===") for passenger in passenger_list: if passenger == target_passenger: print(f"Found {target_passenger}! Stopping search.") break # no point checking further print(f"Not {target_passenger}, checked {passenger}") # --- continue: skip items that don't qualify --- raw_scores = [88, -5, 76, 0, 95, -1, 60] print("\n=== Valid scores only ===") for score in raw_scores: if score <= 0: # invalid scores — skip them continue print(f"Recording score: {score}") # --- for...else: only runs if loop was NOT broken out of --- seating_chart = ["14A", "14B", "15A", "15B"] requested_seat = "16C" print("\n=== Seat search ===") for seat in seating_chart: if seat == requested_seat: print(f"Seat {requested_seat} found!") break else: # This block runs ONLY because we never hit 'break' print(f"Seat {requested_seat} is not available on this flight.")
Not Jake, checked Tom
Not Jake, checked Sara
Found Jake! Stopping search.
=== Valid scores only ===
Recording score: 88
Recording score: 76
Recording score: 95
Recording score: 60
=== Seat search ===
Seat 16C is not available on this flight.
| Aspect | for Loop | while Loop |
|---|---|---|
| Best use case | Known collection or fixed number of iterations | Repeat until a condition changes (unknown count) |
| Risk of infinite loop | Very low — stops when collection is exhausted | High — easy to forget updating the condition |
| Counting built-in | Yes, via range() or enumerate() | No — you manage your own counter |
| Readability | Very readable — intent is obvious | Can be harder to scan quickly |
| Looping over a list | Natural — `for item in my_list` | Possible but awkward with index management |
| Typical example | Process every order in a cart | Keep prompting user until valid input received |
🎯 Key Takeaways
- A for loop visits every item in a collection exactly once — you describe what to do per item, Python handles the counting and advancing automatically.
- range(stop) starts at 0 and excludes the stop value — range(5) gives 0,1,2,3,4. Use range(1, 6) when you need 1 through 5.
- Use enumerate() instead of a manual counter variable — it's cleaner, safer, and signals intent clearly to other developers.
- The for...else clause runs only if the loop was NOT exited via break — it's Python's clean built-in pattern for 'search and handle not-found' logic.
⚠ Common Mistakes to Avoid
- ✕Mistake 1: Modifying a list while looping over it — The loop skips items silently or throws unexpected results because Python's internal pointer gets confused when the list changes under its feet. Fix: loop over a copy (
for item in my_list[:]) or build a new list instead of modifying the original in-place. - ✕Mistake 2: Expecting range(n) to include n — Beginners write
range(10)expecting to see 10 in the output, but they get 0–9. The symptom is being off by one in calculations or missing the last item. Fix: always remember range's stop value is exclusive. Userange(1, 11)to get 1 through 10. - ✕Mistake 3: Using the loop variable after the loop and trusting its value — After a for loop ends, the loop variable still holds the LAST value it was assigned. Beginners sometimes use it assuming it reflects something meaningful. If the loop body never ran (empty list), the variable was never created at all and you'll get a NameError. Fix: if you need a result from a loop, store it explicitly in a variable you control, don't rely on the loop variable post-loop.
Interview Questions on This Topic
- QWhat is the difference between break and continue in a Python for loop, and can you give a practical example of when you'd use each?
- QPython's for loop has an else clause — what does it do, and when does the else block actually execute versus when does it get skipped?
- QIf you need both the index and the value when iterating over a list, what are two ways to do it and which is considered more Pythonic — and why?
Frequently Asked Questions
Can I use a for loop to loop over a string in Python?
Yes, absolutely. A string in Python is a sequence of characters, so for char in 'hello' will visit 'h', 'e', 'l', 'l', 'o' one at a time. This is handy for character-level processing like counting vowels or checking if a string is a palindrome.
What's the difference between for loop and while loop in Python?
Use a for loop when you know in advance what you're iterating over — a list, a range of numbers, a string. Use a while loop when you want to keep repeating until some condition changes and you don't know how many iterations that will take. In practice, for loops cover the majority of everyday repetition tasks.
Why does Python use indentation to define the loop body instead of curly braces?
Python was designed to be readable — indentation makes the structure of the code visually obvious to humans without extra symbols. Everything indented at the same level below the for line is part of the loop body. The moment indentation returns to the previous level, you're outside the loop. This enforces clean, consistent formatting across all Python code.
Written and reviewed by senior developers with real-world experience across enterprise, startup and open-source projects. Every article on TheCodeForge is written to be clear, accurate and genuinely useful — not just SEO filler.