Loops: For and While

Reviewed & published by Brayan K

A loop in Python is a control structure that repeats a block of code multiple times, using a for loop to iterate over a sequence or a while loop to repeat as long as a condition stays true.

Part of the free Python course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

Learn how to make Python repeat tasks automatically using for and while loops.

What You'll Learn in This Lesson

What Are Loops?

Loops let you repeat code multiple times without writing it over and over. Instead of writing print("Hello") 100 times, you can use a loop to do it once.

Think of loops like a washing machine cycle. It repeats the same steps (wash, rinse, spin) until the clothes are clean. Your code works the same way!

Python has two main types of loops:

Use when you know how many times to repeat

"Do this 10 times" or "Do this for each item"

Use when you repeat until a condition changes

"Keep asking until user says stop"

🧠 How Loops Execute: The Mental Model

Before writing loops, build a clear picture of what Python is actually doing each time through. This mental model prevents most beginner loop bugs.

The loop variable is reassigned every iteration

Each time the loop runs, the loop variable gets the next value from the sequence. Python handles this automatically — you just use it.

The indented block is one "iteration"

Everything indented under for or while is the loop body. It runs once per value. Code at the original indentation level runs after the loop finishes.

The loop variable still exists after the loop

After a for loop finishes, the loop variable holds the last value it had. This is sometimes useful — but can also cause bugs if you forget.

Trace through this step by step:

fruits = ["apple", "banana", "cherry"]

for fruit in fruits:
    print(fruit.upper())

print("Done:", fruit)

① fruit = "apple" → prints APPLE

② fruit = "banana" → prints BANANA

③ fruit = "cherry" → prints CHERRY

④ Sequence exhausted → loop exits

⑤ print("Done:", fruit) → Done: cherry

1. The for Loop

The for loop repeats code for each item in a sequence (like a list or range of numbers).

for variable in sequence:

PartDescription
forKeyword that starts the loop
variableHolds the current item (you choose the name)
inKeyword connecting variable to sequence
sequenceWhat to loop over (list, range, string, etc.)
:Required colon at the end
# Loop through a list
fruits = ["apple", "banana", "cherry"]

for fruit in fruits:
    print(f"I like {fruit}!")

print("Done with fruits!")

# The variable 'fruit' takes each value in turn:
# First loop:  fruit = "apple"
# Second loop: fruit = "banana"
# Third loop:  fruit = "cherry"

# ✅ Expected output:
# I like apple!
# I like banana!
# I like cherry!
# Done with fruits!

2. The range() Function

range() generates a sequence of numbers. It's the most common way to repeat code a specific number of times.

SyntaxWhat It ProducesExample
range(stop)0 to stop-1range(5) → 0,1,2,3,4
range(start, stop)start to stop-1range(2, 6) → 2,3,4,5
range(start, stop, step)start to stop-1, by steprange(0, 10, 2) → 0,2,4,6,8
# Different ways to use range()

# Count 0 to 4
print("range(5):")
for i in range(5):
    print(i, end=" ")
print()

# Count 1 to 5
print("\nrange(1, 6):")
for i in range(1, 6):
    print(i, end=" ")
print()

# Count by 2s
print("\nrange(0, 10, 2):")
for i in range(0, 10, 2):
    print(i, end=" ")
print()

# Countdown
print("\nrange(5, 0, -1):")
for i in range(5, 0, -1):
    print(i, end=" ")
print("Blast off!")

# ✅ Expected output:
# range(5):
# 0 1 2 3 4 
#
# range(1, 6):
# 1 2 3 4 5 
#
# range(0, 10, 2):
# 0 2 4 6 8 
#
# range(5, 0, -1):
# 5 4 3 2 1 Blast off!

3. The while Loop

The while loop repeats as long as a condition is True. Use it when you don't know exactly how many times to repeat.

# Basic while loop
count = 1

while count <= 5:
    print(f"Count is: {count}")
    count += 1  # This is crucial! Without it, infinite loop!

print("Loop finished!")

# How it works:
# 1. Check: Is count <= 5? (1 <= 5 = True) → Run code
# 2. Check: Is count <= 5? (2 <= 5 = True) → Run code
# ...continues until...
# 6. Check: Is count <= 5? (6 <= 5 = False) → Exit loop

# ✅ Expected output:
# Count is: 1
# Count is: 2
# Count is: 3
# Count is: 4
# Count is: 5
# Loop finished!

♾️ Infinite Loops and Writing Safe while Loops

An infinite loop runs forever because its condition never becomes False. Your program freezes and you have to force-quit it. Here's how they happen and how to prevent them.

❌ Infinite loop — condition never changes:

count = 1

while count <= 5:
    print(count)
    # ← Forgot count += 1 !
    # count is always 1
    # 1 <= 5 is always True
    # → Runs forever

✅ Safe while loop — guaranteed to exit:

count = 1

while count <= 5:
    print(count)
    count += 1   # ← Update the variable!
    # count grows each iteration
    # Eventually 6 <= 5 → False
    # → Loop exits cleanly

The sentinel value pattern — loop until a special value

A sentinel is a special value that signals "stop". This pattern is everywhere in real programs:

# Keep asking until user types "quit"
responses = ["hello", "how are you", "quit"]  # Simulates user input
index = 0

while True:                         # Intentional infinite loop...
    user_input = responses[index]
    index += 1

    if user_input == "quit":        # ...with a guaranteed exit
        print("Goodbye!")
        break

    print(f"You said: {user_input}")

while True: is valid — an intentional infinite loop is fine as long as you have a break condition inside. This pattern is used for menus, game loops, and server request handling.

Safety net: maximum iteration counter

MAX_TRIES = 1000
tries = 0

while some_condition and tries < MAX_TRIES:
    # ... do work ...
    tries += 1

if tries >= MAX_TRIES:
    print("Warning: hit maximum iterations — check your logic!")

When writing complex while loops, adding a maximum counter is a professional safety habit — it turns an accidental infinite loop into a detectable bug.

4. When to Use for vs while

Use forUse while
You know how many times to repeatYou don't know when to stop
Looping through a list/stringWaiting for user input
"Do this 10 times""Keep going until X happens"
for i in range(10):while not done:

If you can answer "how many times?" → use for If you can answer "until what?" → use while

🧰 Loop Patterns: The Essential Toolkit

Five patterns appear in virtually every program that uses loops. Learn to recognise them and you'll be able to solve most loop problems from memory.

Pattern 1: Accumulator — build a running total

scores = [85, 92, 78, 96, 73]

total = 0               # ← Start at zero
for score in scores:
    total += score      # ← Add each item

average = total / len(scores)
print(f"Total: {total}, Average: {average:.1f}")  # Total: 424, Average: 84.8

Pattern 2: Counter — count items that match a condition

words = ["python", "java", "python", "rust", "python", "go"]

python_count = 0        # ← Start at zero
for word in words:
    if word == "python":
        python_count += 1

print(f"'python' appears {python_count} times")  # 3 times

Pattern 3: Filter — collect items that meet a condition

numbers = [3, -1, 7, -4, 0, 9, -2, 5]

positives = []           # ← Start with empty result
for num in numbers:
    if num > 0:
        positives.append(num)   # ← Add matching items

print(f"Positives: {positives}")  # [3, 7, 9, 5]

Pattern 4: Maximum/Minimum finder

temperatures = [18.5, 22.1, 15.3, 25.8, 19.0, 12.4]

highest = temperatures[0]    # ← Assume first is the answer
for temp in temperatures:
    if temp > highest:
        highest = temp        # ← Update if we find better

print(f"Hottest day: {highest}°C")  # 25.8°C

# Python's built-in does the same:
print(f"Using max(): {max(temperatures)}°C")

Pattern 5: Transform — build a new list from an old one

names = ["alice", "bob", "charlie"]

capitalised = []
for name in names:
    capitalised.append(name.capitalize())

print(capitalised)  # ['Alice', 'Bob', 'Charlie']

You'll soon learn a shorter way to write this using list comprehensions — but the pattern is the same.

5. Loop Control: break and continue

Sometimes you need more control over your loops. Python provides two special keywords:

Exit the loop immediately

Like hitting the emergency stop button

Skip to the next iteration

Like saying "skip this one, move on"

# break - exit the loop early
print("Using break:")
for i in range(10):
    if i == 5:
        print("Found 5! Stopping.")
        break
    print(i)

print("\n" + "="*30 + "\n")

# continue - skip current iteration
print("Using continue (skip even numbers):")
for i in range(10):
    if i % 2 == 0:  # If even
        continue    # Skip to next iteration
    print(i)  # Only prints odd numbers

# ✅ Expected output:
# Using break:
# 0
# 1
# 2
# 3
# 4
# Found 5! Stopping.
#
# ==============================
#
# Using continue (skip even numbers):
# 1
# 3
# 5
# 7
# 9

🔀 The else Clause on Loops — Python's Hidden Feature

Python has a feature almost no other language has: an else block on loops. It sounds confusing at first, but it solves a real problem elegantly.

The else block runs only if the loop completed without hitting a break. If break was triggered, else is skipped entirely.

Without for/else (old way):

names = ["Alice", "Bob", "Charlie"]
search = "Diana"
found = False       # Need a flag variable

for name in names:
    if name == search:
        print("Found!")
        found = True
        break

if not found:       # Check the flag
    print("Not found")

With for/else (Pythonic way):

names = ["Alice", "Bob", "Charlie"]
search = "Diana"

for name in names:
    if name == search:
        print("Found!")
        break
else:               # Runs if no break hit
    print("Not found")

# No flag variable needed!

Real use case: searching for a prime number factor

def is_prime(n):
    if n < 2:
        return False
    for i in range(2, int(n ** 0.5) + 1):
        if n % i == 0:
            print(f"{n} is divisible by {i} — not prime")
            break
    else:
        print(f"{n} is prime!")   # Only runs if no factor was found
        return True
    return False

is_prime(17)   # 17 is prime!
is_prime(15)   # 15 is divisible by 3 — not prime

6. Looping Through Different Data Types

You can loop through many types of sequences in Python:

Data TypeWhat You Get Each Iteration
ListEach item in the list
StringEach character
DictionaryEach key (or use .items() for key-value pairs)
range()Each number in the sequence
# Loop through a string
print("Characters in 'Hello':")
for char in "Hello":
    print(char, end=" ")
print()

# Loop through a dictionary
print("\nPerson info:")
person = {"name": "Alice", "age": 25, "city": "Paris"}
for key, value in person.items():
    print(f"  {key}: {value}")

# Use enumerate() to get index + value
print("\nWith index:")
colors = ["red", "green", "blue"]
for i, color in enumerate(colors):
    print(f"  {i}: {color}")

# ✅ Expected output:
# Characters in 'Hello':
# H e l l o 
#
# Person info:
#   name: Alice
#   age: 25
#   city: Paris
#
# With index:
#   0: red
#   1: green
#   2: blue

🔧 Loop Helpers: enumerate(), zip(), and reversed()

Python includes several built-in functions that make loops dramatically more powerful and readable. These are used constantly in real code.

enumerate() — get the index alongside the value

Without it, you'd need a manual counter variable. With it, Python tracks the index for you:

Old way (manual counter):

players = ["Alice", "Bob", "Charlie"]
i = 0
for player in players:
    print(f"{i+1}. {player}")
    i += 1
players = ["Alice", "Bob", "Charlie"]
for i, player in enumerate(players, start=1):
    print(f"{i}. {player}")
# 1. Alice
# 2. Bob
# 3. Charlie

The start=1 argument makes numbering start at 1 instead of 0 — perfect for user-facing lists.

zip() — loop through two sequences in parallel

zip() pairs up items from two (or more) sequences, giving you one item from each per iteration:

names  = ["Alice", "Bob",   "Charlie"]
scores = [92,      78,      85]

for name, score in zip(names, scores):
    grade = "Pass" if score >= 60 else "Fail"
    print(f"{name}: {score}/100 — {grade}")

# Output:
# Alice: 92/100 — Pass
# Bob: 78/100 — Pass
# Charlie: 85/100 — Pass

zip() stops at the shortest sequence. If one list has 3 items and another has 5, you get 3 pairs.

reversed() — loop backwards through a sequence

steps = ["Open app", "Log in", "Browse", "Checkout", "Pay"]

print("Reverse order:")
for step in reversed(steps):
    print(f"  ← {step}")

# Countdown using reversed() with range:
for i in reversed(range(1, 6)):
    print(i, end=" ")
print("Go!")  # 5 4 3 2 1 Go!

Remember: these are all "iterables"

Lists, strings, range(), enumerate(), zip(), and reversed() are all things Python can loop over. The technical term is iterable. Any time you use for x in ___, the blank must be an iterable.

7. Nested Loops (Loop Inside a Loop)

You can put a loop inside another loop. The inner loop runs completely for each iteration of the outer loop.

How nested loops work:

Outer loop runs once → Inner loop runs completely Outer loop runs again → Inner loop runs completely again ...and so on

# Nested loop example - multiplication table
print("3x3 Multiplication Table:")
print("-" * 15)

for i in range(1, 4):       # Outer: rows 1, 2, 3
    for j in range(1, 4):   # Inner: columns 1, 2, 3
        result = i * j
        print(f"{i}x{j}={result}", end="  ")
    print()  # New line after each row

# How many times does the inner code run?
# 3 (outer) × 3 (inner) = 9 times

# ✅ Expected output:
# 3x3 Multiplication Table:
# ---------------
# 1x1=1  1x2=2  1x3=3  
# 2x1=2  2x2=4  2x3=6  
# 3x1=3  3x2=6  3x3=9

⚡ List Comprehensions: The Pythonic Way to Build Lists

A list comprehension is a compact, one-line way to build a list using a loop — and it's one of the most distinctly "Pythonic" features of the language. Once you understand them, you'll use them constantly.

The transformation: for loop → list comprehension

Traditional for loop (4 lines):

numbers = [1, 2, 3, 4, 5]
squared = []
for n in numbers:
    squared.append(n ** 2)
# squared = [1, 4, 9, 16, 25]

List comprehension (1 line — same result):

numbers = [1, 2, 3, 4, 5]
squared = [n ** 2 for n in numbers]
# squared = [1, 4, 9, 16, 25]

With a filter condition

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# Only keep even numbers:
evens = [n for n in numbers if n % 2 == 0]
print(evens)   # [2, 4, 6, 8, 10]

# Square only the odd numbers:
odd_squares = [n ** 2 for n in numbers if n % 2 != 0]
print(odd_squares)   # [1, 9, 25, 49, 81]

# Capitalise names that are longer than 4 letters:
names = ["Ali", "Bobby", "Charlie", "Di"]
long_names = [name.upper() for name in names if len(name) > 4]
print(long_names)   # ['BOBBY', 'CHARLIE']

Common Mistakes to Avoid

Forgetting to update the condition in while loops

This causes infinite loops! Always change something inside the loop.

Off-by-one errors with range()

range(5) gives 0-4, not 1-5. Use range(1, 6) for 1-5.

Modifying a list while looping through it

This can cause unexpected behavior. Loop through a copy instead.

Using = instead of == in conditions

while x = 5: is wrong. Use while x == 5:

8. Practical Examples

Example 1: Sum of Numbers

# Calculate sum of 1 to 100
total = 0

for num in range(1, 101):
    total += num

print(f"Sum of 1 to 100 = {total}")

# Using Python's built-in (faster):
print(f"Using sum(): {sum(range(1, 101))}")

# ✅ Expected output:
# Sum of 1 to 100 = 5050
# Using sum(): 5050

Example 2: Find an Item

# Search for an item in a list
names = ["Alice", "Bob", "Charlie", "Diana"]
search_for = "Charlie"
found = False

for name in names:
    if name == search_for:
        print(f"Found {search_for}!")
        found = True
        break

if not found:
    print(f"{search_for} not in list.")

# ✅ Expected output:
# Found Charlie!

Example 3: Password Attempts

# Simulate login attempts
correct_password = "secret123"
max_attempts = 3
attempts = 0

# Simulating different password guesses
guesses = ["wrong", "also_wrong", "secret123"]

while attempts < max_attempts:
    guess = guesses[attempts]  # Simulate user input
    attempts += 1
    
    if guess == correct_password:
        print(f"Login successful on attempt {attempts}!")
        break
    else:
        remaining = max_attempts - attempts
        print(f"Wrong password. {remaining} attempts left.")
else:
    print("Account locked!")

# ✅ Expected output:
# Wrong password. 2 attempts left.
# Wrong password. 1 attempts left.
# Login successful on attempt 3!
# 🎯 YOUR TURN — replace each ___ using the hint beside it.

prices = [4.50, 0.00, 12.99, 3.20, 0.00, 25.00, 7.75]
card_cap = 40.00

total = 0.0
scanned = 0

# 1) You want the position AND the value, so wrap the list in this.
for i, price in ___(prices):           # 👉 replace ___ with enumerate

    # 2) A voided line is 0.00 — skip to the next turn of the loop.
    if price == 0.00:
        ___                            # 👉 replace ___ with continue

    # 3) Adding this one would pass the cap, so leave the loop entirely.
    if total + price > card_cap:
        print(f"Line {i} would pass the cap - stopping")
        ___                            # 👉 replace ___ with break

    total += price
    scanned += 1

print("Items rung up:", scanned)
print(f"Total: {total:.2f}")

# 4) Count DOWN from 3 to 1: start, stop-before, step.
for countdown in ___(3, 0, -1):        # 👉 replace ___ with range
    print("Printing receipt in", countdown)

names = ["ada", "ben", "cara"]

# 5) One output per input, written on one line.
shouted = [n.upper() ___ n in names]   # 👉 replace ___ with for
print("Shouted:", shouted)

# A for/else: else runs only when the loop was never broken out of.
for name in names:
    if name.startswith("z"):
        break
else:
    print("No name started with z")

# ✅ Expected output:
# Line 5 would pass the cap - stopping
# Items rung up: 3
# Total: 20.69
# Printing receipt in 3
# Printing receipt in 2
# Printing receipt in 1
# Shouted: ['ADA', 'BEN', 'CARA']
# No name started with z

Mini-Project: FizzBuzz and Number Analysis

FizzBuzz is the most famous beginner programming challenge — it's used in real job interviews to test basic loop and condition logic. If you can write FizzBuzz, you understand loops.

Classic FizzBuzz — uses: for loop, range(), modulo, if/elif/else

for i in range(1, 101):
    if i % 3 == 0 and i % 5 == 0:
        print("FizzBuzz")
    elif i % 3 == 0:
        print("Fizz")
    elif i % 5 == 0:
        print("Buzz")
    else:
        print(i)

Extended version — adds: accumulator, counter, filter patterns

# FizzBuzz with statistics
fizz_count   = 0
buzz_count   = 0
fizzbuzz_count = 0
number_sum   = 0    # Sum of numbers that printed as numbers

for i in range(1, 101):
    if i % 15 == 0:
        print("FizzBuzz", end="  ")
        fizzbuzz_count += 1
    elif i % 3 == 0:
        print("Fizz", end="  ")
        fizz_count += 1
    elif i % 5 == 0:
        print("Buzz", end="  ")
        buzz_count += 1
    else:
        print(i, end="  ")
        number_sum += i

print("\n\n=== Statistics ===")
print(f"Fizz:     {fizz_count} times")
print(f"Buzz:     {buzz_count} times")
print(f"FizzBuzz: {fizzbuzz_count} times")
print(f"Numbers:  {100 - fizz_count - buzz_count - fizzbuzz_count}")
print(f"Sum of plain numbers: {number_sum}")

Concepts used in this project:

Challenge: Can you rewrite the FizzBuzz output using a list comprehension? Hint: you'll need the ternary operator from the Control Flow lesson.

Summary: Quick Reference

ConceptWhat It DoesExample
forLoop through a sequencefor x in list:
whileLoop while condition is Truewhile x < 10:
range()Generate number sequencerange(1, 10, 2)
breakExit loop immediatelyif done: break
continueSkip to next iterationif skip: continue
enumerate()Get index + valuefor i, x in enumerate(list):

Beginner Track Complete!

Congratulations! You've completed the Python basics. You now know:

🏆 Beginner Track Complete! You've mastered the fundamentals!

Variables, operators, conditions, and loops — these 5 lessons are the foundation of all programming. Every Python developer in the world uses these exact same tools every single day.

Practice quiz

Which loop is best when you know exactly how many times to repeat?

  • while loop
  • do-while loop
  • for loop
  • repeat loop

Answer: for loop. A for loop is used when you know how many times (or which items) to iterate over.

What numbers does range(5) produce?

  • 0, 1, 2, 3, 4
  • 1, 2, 3, 4, 5
  • 0, 1, 2, 3, 4, 5
  • 5

Answer: 0, 1, 2, 3, 4. range(5) goes from 0 to 4 — the stop value is NOT included.

What does range(2, 6) produce?

  • 2, 3, 4, 5, 6
  • 2, 6
  • 0, 1, 2, 3, 4, 5
  • 2, 3, 4, 5

Answer: 2, 3, 4, 5. range(start, stop) gives start up to stop-1: 2, 3, 4, 5.

What does range(0, 10, 2) produce?

  • 0, 2, 4, 6, 8, 10
  • 0, 2, 4, 6, 8
  • 0, 1, 2, ..., 10
  • 2, 4, 6, 8

Answer: 0, 2, 4, 6, 8. The step of 2 yields even numbers from 0 up to (but not including) 10.

What does the 'break' keyword do inside a loop?

  • Exits the loop immediately
  • Skips the current iteration
  • Restarts the loop
  • Pauses the loop

Answer: Exits the loop immediately. break exits the loop immediately, skipping any remaining iterations.

What does the 'continue' keyword do?

  • Exits the loop
  • Ends the program
  • Skips to the next iteration
  • Repeats the current item

Answer: Skips to the next iteration. continue skips the rest of the current iteration and moves to the next one.

What causes an infinite while loop?

  • Using range()
  • The condition never becoming False
  • Using break
  • Too many items

Answer: The condition never becoming False. If the while condition never becomes False (e.g. you forget to update the variable), it runs forever.

Which loop should you use to 'keep asking until the user types quit'?

  • for loop
  • range loop
  • nested loop
  • while loop

Answer: while loop. A while loop repeats until a condition changes — ideal when you don't know how many iterations.

After 'for fruit in ["a", "b", "c"]:' finishes, what value does fruit hold?

  • 'a'
  • 'c'
  • None
  • It no longer exists

Answer: 'c'. The loop variable keeps the last value it took, 'c', after the loop ends.

Is 'while True:' with a break inside considered valid Python?

  • No, it always errors
  • Only in functions
  • Yes, an intentional infinite loop with a break exit is fine
  • Only with range()

Answer: Yes, an intentional infinite loop with a break exit is fine. while True: is valid as long as a break (or return) eventually exits it.

Continue this course