Skip to content
C Codeloom
Python

While Loops, break, and continue in Python

A clear guide to Python while loops — condition-driven iteration, break and continue, the else clause, infinite loops, and patterns for safe, terminating code.

·8 min read · By Yash Kesharwani
Intermediate 9 min read

What you'll learn

  • When to choose a while loop over a for loop
  • How break and continue change control flow
  • How to use the else clause on a while loop
  • How to write safe infinite loops with break
  • Common patterns: retry, polling, input validation

Prerequisites

A for loop is the right tool when you know what you are iterating over. A while loop is the right tool when you do not — when the number of iterations depends on a condition you check as you go. This post covers the while syntax, the control-flow keywords that pair with it, and the patterns where while is the natural choice.

The basic while loop

A while loop runs its body as long as a condition is true:

count = 0
while count < 5:
    print(count)
    count += 1

The condition is checked before each iteration. If it is false the first time, the body never runs at all:

n = 10
while n < 5:
    print("never runs")

Three things must be true for a while loop to behave well:

  1. The condition is meaningful when the loop starts.
  2. Something in the body moves toward making the condition false.
  3. The exit condition is genuinely reachable.

Forgetting point two produces the most common bug with while: the infinite loop.

while vs for

Use for when the iteration count is known or comes from an iterable. Use while when continuation depends on a condition checked each pass — a value still being too large, a queue still being non-empty, a user still entering invalid input.

# for is awkward — we don't know how long this takes
import random
attempts = 0
while True:
    attempts += 1
    if random.random() < 0.1:
        break
print(f"Took {attempts} attempts.")

If you find yourself faking for semantics with while (incrementing a counter, comparing against a length), reach for for and range instead.

break and continue

Both keywords change loop flow, and both work in while and for.

  • break exits the loop immediately.
  • continue skips the rest of the body and re-checks the condition.
# Read numbers until the user types "quit"
total = 0
while True:
    raw = input("Number (or 'quit'): ")
    if raw == "quit":
        break
    if not raw.strip().lstrip("-").isdigit():
        print("Not a number, try again.")
        continue
    total += int(raw)

print("Total:", total)

The shape of this loop — while True with one or more break conditions inside — is a deliberate, idiomatic pattern, not laziness. It puts the exit conditions next to the code that detects them.

The while ... else clause

Like for, while has an optional else clause that runs when the loop ends without a break:

def has_factor(n, limit):
    i = 2
    while i < limit:
        if n % i == 0:
            print(f"{n} is divisible by {i}")
            break
        i += 1
    else:
        print(f"{n} has no small factors below {limit}")

has_factor(15, 10)    # 15 is divisible by 3
has_factor(13, 10)    # 13 has no small factors below 10

It is occasionally clarifying for search loops. Use sparingly and document when you do.

Infinite loops, intentional and otherwise

while True: is the explicit way to write a loop that runs until a break. This is appropriate when:

  • The exit condition is easier to express in the body than in the header.
  • There are multiple exit conditions.
  • You are running an event loop, a server, or a polling worker.
while True:
    job = queue.get()
    if job is None:
        break
    process(job)

Unintentional infinite loops, by contrast, are usually a missing update:

# Bug: count never changes
count = 0
while count < 5:
    print(count)
    # forgot count += 1

If you hit one, interrupt with Ctrl+C. When debugging, print the loop variable on each iteration — it makes the missing update obvious.

Try it yourself. Write a guessing game. Pick a secret number with import random; secret = random.randint(1, 100). Loop with while True, read a guess with input, and break when the guess matches. Print “too high” or “too low” on each wrong guess, and count attempts.

Pattern: input validation

A common job for while is asking the user for input until they give something valid:

def ask_age():
    while True:
        raw = input("Enter your age: ")
        if raw.isdigit():
            age = int(raw)
            if 0 < age < 130:
                return age
        print("Please enter a whole number between 1 and 129.")

Returning from inside the loop is clean. No flag variable, no second condition, no surprises. See Python Conditionals for more on the early-return style.

Pattern: retry with limit

When an operation may fail transiently, wrap it in a bounded retry:

import time

def fetch(url, retries=3, delay=1.0):
    attempt = 0
    while attempt < retries:
        result = try_fetch(url)
        if result is not None:
            return result
        attempt += 1
        time.sleep(delay)
    raise RuntimeError(f"Failed to fetch {url} after {retries} attempts.")

Always bound the number of retries. An unbounded retry loop becomes a denial-of-service against your own program.

Pattern: consume until empty

When working with a mutable queue or stack, while reads naturally:

stack = [1, 2, 3, 4, 5]
while stack:
    top = stack.pop()
    print(top)
# 5 4 3 2 1

while stack: uses the truthy/falsy rule covered in Conditionals — an empty list is falsy, so the loop exits when the stack is empty.

Pattern: convergence

Numerical algorithms often loop until a value stops changing meaningfully. Newton’s method for square roots, for example:

def sqrt(n, tol=1e-10):
    if n < 0:
        raise ValueError("n must be non-negative")
    x = n if n >= 1 else 1.0
    while abs(x * x - n) > tol:
        x = (x + n / x) / 2
    return x

print(sqrt(2))     # 1.4142135623730951
print(sqrt(100))   # 10.0

A tolerance — not exact equality — is the right exit condition. Floats rarely become exactly equal; see Comparison and Logical Operators for why.

Try it yourself. Write a function count_digits(n) that returns how many digits the non-negative integer n has. Use while n > 0: n //= 10 and a counter. Handle the special case n == 0 (which has one digit).

Nested loops and break

break only exits the innermost loop. To exit several at once, refactor into a function and use return:

def find(grid, target):
    for r, row in enumerate(grid):
        for c, value in enumerate(row):
            if value == target:
                return (r, c)
    return None

print(find([[1, 2], [3, 4]], 3))    # (1, 0)

Trying to thread a flag variable through two nested loops is more code and less clear. Functions are the right tool.

A worked example

A small console “menu” loop that combines several patterns from this post:

def show_menu():
    print()
    print("1. Add task")
    print("2. List tasks")
    print("3. Remove task")
    print("4. Quit")

def run():
    tasks = []
    while True:
        show_menu()
        choice = input("Choose: ").strip()

        if choice == "1":
            task = input("Task description: ").strip()
            if not task:
                print("Empty task ignored.")
                continue
            tasks.append(task)

        elif choice == "2":
            if not tasks:
                print("No tasks yet.")
                continue
            for i, task in enumerate(tasks, start=1):
                print(f"  {i}. {task}")

        elif choice == "3":
            raw = input("Number to remove: ").strip()
            if not raw.isdigit():
                print("Not a number.")
                continue
            idx = int(raw) - 1
            if 0 <= idx < len(tasks):
                removed = tasks.pop(idx)
                print(f"Removed: {removed}")
            else:
                print("Out of range.")

        elif choice == "4":
            print("Goodbye.")
            break

        else:
            print("Unknown option.")

# run()    # uncomment to run interactively

The outer while True loop runs until the user picks “Quit.” continue is used liberally to skip back to the menu after invalid input. Each branch is short because each one only handles its own case.

Recap

You now know:

  • while checks a condition before each iteration; the body must make progress toward exit
  • Use while when iteration depends on a condition, not a known sequence
  • break exits the loop; continue skips to the next check
  • while True: ... break is an idiomatic pattern for multi-exit loops
  • while ... else runs if no break occurred
  • Bound your retry loops; consume mutable containers with while container:
  • break only exits the innermost loop — use return to leave nested ones

Next steps

You now have the full toolkit for conditionals and loops. The next post moves to the other major dimension of structuring code: functions. We will cover def, return, arguments, and the habits that make functions worth reusing.

→ Next: Functions in Python — def, return, and Arguments

Questions or feedback? Email codeloomdevv@gmail.com.