🐍 Python

Python While Loop — The Complete Guide

Syntax, while-else, break/continue/pass, infinite loops, nested loops, and exactly where a while loop beats a for loop — explained with real bugs, not textbook definitions.

📅

Last Updated

July 2026

⏱️

Read Time

28 min

🎯

Level

Beginner

What Is a While Loop in Python?

A while loop repeats a block of code for as long as a given condition stays True. That's the one-line definition. The part that actually matters in practice: unlike a for loop, which knows in advance how many times it's going to run because it's iterating over something with a known length, a while loop has no idea how many iterations it'll take. It just keeps checking the condition, over and over, until something inside the loop changes to make that condition false. That difference — known iteration count versus unknown — is the entire reason to pick one over the other, and most beginners never get told this explicitly.

Here's my honestly opinionated take, up front: a huge number of while loops I see in beginner code should actually be for loops, and a smaller but more dangerous number of for loops I see in intermediate code should actually be while loops. People reach for whichever one they learned first and force every problem into that shape. The real rule is simple — if you know the exact number of iterations ahead of time (a fixed range, a list, a file's lines), use for. If you're waiting for something to happen — a condition to flip, a sentinel value to show up, a retry to succeed — use while. Everything else in this guide is detail on top of that one decision.

🐍 Pythonbasic_while.py
count = 0
while count < 5:
    print(f"Count is {count}")
    count += 1

print("Loop finished")

Output

Count is 0 Count is 1 Count is 2 Count is 3 Count is 4 Loop finished

How a While Loop Actually Executes

Under the hood, a while loop does exactly three things, repeated in a cycle: evaluate the condition, run the body if it's True, jump back to re-evaluate the condition. That's it. There's no hidden counter, no implicit iterator, no magic. This is precisely why while loops give you the most control of any looping construct in Python — and also precisely why they're the easiest to get wrong. Nothing stops the condition from staying True forever except your own code inside the loop body actually changing something the condition depends on.

The condition itself doesn't have to be a comparison like count < 5. It can be any expression Python can evaluate as truthy or falsy — a boolean variable, a non-empty list, a function call that returns a boolean, even a complex expression combining several conditions with and/or. Python evaluates the whole expression fresh, every single time, before deciding whether to run the body again.

While Loop Execution Flow — Flowchart

The diagram below is the mental model to keep in your head every single time you write a while loop, especially when you're debugging one that won't stop, or one that never runs at all.

🏁 StartEnter the while statement
begin
❓ Evaluate conditionwhile condition:
check condition
✅ Condition is True?Checked fresh every cycle
True ✓
▶️ Run loop bodyIndented block executes
check for break
🔁 Jump back to conditionNo automatic increment — you control this
re-evaluate condition
🚪 break encountered?Exits loop immediately, skips else
break hit — skip else entirely
🍃 Run else block (if present)Only runs if loop ended WITHOUT break
else block done
🏁 Continue after the loopCode after the while block resumes

Code Execution Flow — from source to output

The step people miss most in that diagram: there is no automatic increment anywhere in this flow. A for loop over range(5) advances its counter for you, automatically, every cycle. A while loop does absolutely nothing to move itself forward — if you forget the line that updates whatever the condition depends on, the loop runs forever. That single missing line is, without exaggeration, the most common bug beginners write with while loops, and it's the reason this guide spends an entire section on infinite loops later.

The while-else Clause (The Most Misunderstood Feature in Python)

Python lets you attach an else block to a while loop, and I guarantee this is new information for a good chunk of people reading this, even people who've been writing Python for years. The else block runs only if the loop finished normally — meaning the condition eventually became False on its own, without a break statement cutting the loop short. If a break fires anywhere inside the loop body, the else block is skipped entirely.

🐍 Pythonwhile_else_search.py
numbers = [4, 8, 15, 16, 23, 42]
target = 99

i = 0
while i < len(numbers):
    if numbers[i] == target:
        print(f"Found {target} at index {i}")
        break
    i += 1
else:
    print(f"{target} was not found in the list")

print("Search complete")

Output

99 was not found in the list Search complete

This is genuinely the cleanest use case for while-else: a search loop where you need to distinguish between "found it, stopped early" and "looked through everything, never found it." Without else, you'd typically need a separate flag variable — something like found = False, set to True right before the break, then checked after the loop. The else clause removes that flag variable entirely. My honest take: I still think most developers, including experienced ones, avoid while-else because the naming is confusing — it reads like "else if the while loop is false," not "else if the loop never broke," and that mismatch between the keyword and its actual meaning causes more hesitation than the feature deserves. Learn it once, and it's genuinely useful in this exact search pattern.

break, continue, and pass — Loop Control Statements

Three keywords control the flow inside any loop body, and mixing them up is an easy mistake to make when you're moving fast.

  • break — exits the loop immediately, skipping any remaining code in the body and skipping the else clause entirely. The loop stops as if the condition had just become False.

  • continue — skips the rest of the current iteration's body and jumps straight back to re-checking the loop condition. The loop keeps running; it just doesn't finish executing the current pass through the body.

  • pass — does literally nothing. It's a no-op placeholder, used when Python's syntax requires an indented block but you don't have any code to put there yet.

🐍 Pythonbreak_continue_pass.py
n = 0
while n < 10:
    n += 1
    if n == 3:
        continue          # skip printing 3, but keep looping
    if n == 7:
        break             # stop the loop entirely once n hits 7
    if n == 5:
        pass              # placeholder, does nothing special here
    print(n)

print("Done")

Output

1 2 4 5 6 Done

The continue Trap — Forgetting the Increment

This is a real bug, and it's specific to while loops in a way it isn't for for loops. If your increment statement (n += 1) sits AFTER a continue check but the increment is what triggers the condition that leads to continue, you can accidentally skip the increment and freeze the loop forever. The fix, as shown above, is to put the increment as the very first thing in the loop body, before any conditional logic that might continue. Get this order backwards and you'll be staring at a script that's just hanging, no error, no output, no obvious clue why — until you notice the counter variable never actually changes.

🐍 Pythoncontinue_infinite_bug.py
# BUGGY VERSION — this hangs forever
n = 0
while n < 5:
    if n == 2:
        continue      # jumps back WITHOUT reaching n += 1 below
    print(n)
    n += 1        # never reached when n == 2, loop freezes at n=2 forever

Infinite Loops — Intentional vs Accidental

An infinite loop is any loop whose condition never becomes False. Sometimes that's exactly what you want. Most of the time, when a beginner hits one, it's a bug, and it's usually one of two causes: either the variable the condition depends on never actually gets updated inside the loop body, or the update happens but never moves the condition toward becoming false (incrementing in the wrong direction, comparing against the wrong value, or updating a different variable than the one the condition checks).

Intentional Infinite Loops — while True:

The while True: pattern is one of the most common idioms in real Python code, and it's completely legitimate. Web servers, chat bots, game loops, and command-line tools that keep prompting for input all rely on a loop that runs forever by design, exiting only through an explicit break somewhere inside based on real logic — not through the condition itself ever going false.

🐍 Pythonwhile_true_pattern.py
while True:
    user_input = input("Enter a command ('quit' to exit): ")
    if user_input.lower() == "quit":
        print("Goodbye!")
        break
    print(f"You typed: {user_input}")

This pattern is arguably clearer than trying to cram the exit condition into the while line itself, especially when the actual exit logic needs to run some code first (like printing "Goodbye!") before actually leaving. It's the same idea we saw earlier with the walrus operator solving the "read input, then check it" problem — while True plus an internal break is the more general, more flexible version of that same pattern.

Accidental Infinite Loops — The Real Debugging Scenario

Here's a genuinely common accidental version. Someone's building a retry loop for a flaky API call, and they write the retry counter update inside an if block that only runs on success — meaning on every failure, the counter never advances, and the loop just keeps hammering the same failing request indefinitely, forever, until someone notices the process is stuck and has to Ctrl+C it in the terminal (or worse, notices it in a production log an hour later, after it's already burned through a rate limit or run up a cloud bill).

🐍 Pythonretry_loop_bug.py
# BUGGY — attempts never increments on failure, loops forever
attempts = 0
max_attempts = 5
success = False

while attempts < max_attempts and not success:
    result = call_flaky_api()   # imagine this sometimes fails
    if result.ok:
        success = True
        attempts += 1            # BUG: only increments on success

# FIXED — attempts increments regardless of outcome
attempts = 0
while attempts < max_attempts and not success:
    result = call_flaky_api()
    attempts += 1                # always runs, guarantees the loop terminates
    if result.ok:
        success = True

The fix is a one-line move — pull the increment out of the conditional block and make it unconditional. The general lesson: whatever variable your while condition checks, make sure the thing that updates it runs on every single pass through the loop, not just the happy path. If you catch yourself writing an increment inside an if block, stop and ask whether the loop can still terminate on the branch where that if doesn't fire.

How to Actually Kill a Runaway Loop

If you've run a script and it's just sitting there, not responding, not printing anything, that's almost always an infinite loop. In a terminal, Ctrl+C sends a KeyboardInterrupt which will stop most stuck Python scripts immediately. In a Jupyter Notebook, use the Kernel → Interrupt option, or the stop (square) button, since Ctrl+C in a notebook cell usually doesn't do what you expect. If neither works because the loop is stuck inside a C extension call that doesn't check for interrupts, you may genuinely need to kill the process from your OS's task manager or with kill -9 <pid> on Linux/macOS.

Nested While Loops

You can put a while loop inside another while loop, same as with for loops. The inner loop runs to completion on every single pass of the outer loop. This is genuinely useful for grid-based logic, matrix traversal, or any two-dimensional problem, but it comes with a real performance warning: if the outer loop runs n times and the inner loop runs m times on each pass, your total work is n * m, not n + m. That difference is easy to underestimate until you're staring at a script that's technically correct but takes eleven minutes to process what should've taken two seconds.

🐍 Pythonnested_while.py
row = 1
while row <= 3:
    col = 1
    while col <= 3:
        print(f"({row},{col})", end=" ")
        col += 1
    print()          # newline after each row
    row += 1

Output

(1,1) (1,2) (1,3) (2,1) (2,2) (2,3) (3,1) (3,2) (3,3)

break Only Exits the Innermost Loop

This is another real gotcha. A break inside a nested loop only exits the loop it's directly written inside — it does NOT jump out of both loops at once, even though a lot of people intuitively expect it to. If you need to break out of two or more nested loops simultaneously, you generally need either a flag variable checked in the outer loop's condition, or you wrap the whole thing in a function and use return to exit everything at once, which is honestly the cleaner option in most real code.

🐍 Pythonbreak_only_inner.py
found = False
row = 0
while row < 3 and not found:
    col = 0
    while col < 3:
        if row == 1 and col == 1:
            found = True
            break          # only exits the INNER while loop
        col += 1
    row += 1

print(f"Match found: {found}, stopped at row={row}")

Output

Match found: True, stopped at row=2

While Loop vs For Loop — When to Use Which

This decision comes up constantly, and getting it wrong doesn't usually crash your program — it just makes the code harder to read and occasionally introduces the exact infinite-loop bugs covered above.

SituationUse whileUse for
Known number of iterations (fixed range)❌ Unnecessary complexity✅ Yes — for i in range(n)
Iterating over a list, string, dict, or file❌ Requires manual index tracking✅ Yes — for item in collection
Waiting for a condition to become true/false✅ Yes — this is the exact use case❌ Not naturally expressible
Retry logic with a max attempt count✅ Yes — combine condition with a counter⚠️ Possible but awkward
Reading input until a sentinel value✅ Yes — classic while True + break pattern❌ Doesn't fit naturally
Risk of accidental infinite loop⚠️ Higher — you control termination manually✅ Lower — iterator handles termination

The short version, if you only remember one sentence from this whole section: for loops iterate over something, while loops wait for something. If you find yourself writing i = 0 before a while loop and i += 1 inside it just to count up to a fixed number, stop — that's a for i in range(n): wearing a disguise, and the for-loop version is both shorter and structurally incapable of becoming an infinite loop by accident.

Try It Yourself — While Loop Playground

Edit the snippet below. Try changing the condition, removing the increment (carefully — you'll need to stop the runtime if it hangs), or adding a break partway through.

🐍 Pythonwhile_demo.py
balance = 1000
withdrawal = 150

while balance >= withdrawal:
    balance -= withdrawal
    print(f"Withdrew {withdrawal}, remaining balance: {balance}")

print(f"Final balance: {balance} (not enough left for another withdrawal)")

Output

Withdrew 150, remaining balance: 850 Withdrew 150, remaining balance: 700 Withdrew 150, remaining balance: 550 Withdrew 150, remaining balance: 400 Withdrew 150, remaining balance: 250 Withdrew 150, remaining balance: 100 Final balance: 100 (not enough left for another withdrawal)

Practice This Code — Live Editor

Where While Loops Actually Show Up in Real Code

  • Retry logic for network calls — while attempts < max_retries and not success: is the standard shape for calling a flaky API or a database connection that might briefly be unavailable.

  • Reading from a stream until it's exhausted — while chunk := file.read(1024): reads a file in fixed-size chunks until nothing's left, combining the walrus operator with a while loop for a clean one-liner.

  • Game loops — while game_running: is the literal backbone of nearly every game built with Pygame or similar libraries, running every frame until the player quits.

  • Command-line REPLs and interactive tools — while True: prompting for input and breaking on an exit command is the standard pattern for any interactive CLI tool.

  • Polling for a background job to finish — while not job.is_complete(): time.sleep(2) is common in scripts checking on a long-running cloud task, a Celery worker, or a batch processing job.

  • Binary search and other unknown-iteration-count algorithms — algorithms like binary search naturally use while low <= high: because the exact number of iterations depends on the data, not a fixed range.

  • Server main loops — a basic socket server's core loop (while True: conn, addr = server.accept()) that keeps accepting new connections indefinitely.

Do's and Don'ts With While Loops

✅ Advantages
Update the loop condition variable unconditionallyWhatever the while condition checks, make sure the update happens on every pass, not buried inside a conditional branch that might not run.
Use while True + break for input/event loopsIt's clearer than cramming complex exit logic into the condition line itself, especially when the exit path needs to run cleanup code first.
Add a max-iteration safety cap on retry loopswhile attempts < max_attempts protects you from truly infinite retries against a service that's permanently down, not just temporarily flaky.
Prefer for loops for known, fixed iteration countsIf you're manually tracking an index just to count to a fixed number, that's almost always better expressed as a for loop.
Use while-else for search-and-stop patternsIt removes the need for a separate 'found' flag variable when you need to distinguish an early break from a natural loop completion.
❌ Disadvantages
Don't put the increment inside a conditional branchIf the update only runs on one branch of an if statement inside the loop, the other branch can freeze the loop forever — a very common accidental infinite loop.
Don't assume break exits all nested loopsbreak only exits the innermost loop it's written in. Use a flag variable or wrap the loops in a function with return for multi-level exits.
Don't forget while True: needs an explicit exit pathEvery intentional infinite loop needs a break (or a return, or an exception) reachable somewhere inside it, or your program truly never terminates.
Don't rely on while-else without understanding it firstThe else block only skips when break fires — it's easy to misuse if you assume it behaves like an if/else pair.
Don't use a while loop just to iterate over a known collectionfor item in my_list: is shorter, clearer, and can't accidentally become infinite the way a manually-indexed while loop can.

Python While Loop — Interview Questions

Practice Questions — Test Your Understanding

1. What does this loop print? i = 0; while i < 3: print(i); i += 1

Easy

2. Why does this loop never terminate? x = 10; while x > 0: print(x); x += 1

Easy

3. What's the output of: n = 5; while n > 0: n -= 1; if n == 2: continue; print(n)

Medium

4. Does the else block run in this code? i = 0; while i < 3: i += 1; if i == 2: break; else: print('done')

Medium

5. What happens if you write while [1, 2, 3]: instead of a boolean condition?

Medium

6. In nested while loops, does a single break in the inner loop stop the outer loop too?

Medium

7. Rewrite this while loop as a for loop: i = 0; total = 0; while i < 10: total += i; i += 1

Hard

8. Why might while chunk := file.read(1024): be preferred over a manual while True with a break for reading a file?

Hard

Conclusion — Mastering the While Loop

The while loop is the simplest looping construct in Python to describe and, honestly, one of the easiest to get subtly wrong. There's no safety net — no automatic iterator managing termination for you the way a for loop has. That's exactly what makes it powerful for the situations where you genuinely don't know how many iterations you need, and exactly what makes it dangerous when you use it for situations where you do.

If there's one habit worth carrying forward from this entire guide, it's this: every time you write a while loop, before you move on, trace through in your head exactly which line updates the condition, and confirm that line runs on every single pass, not just the happy path. That one check catches the overwhelming majority of infinite-loop bugs before they ever reach production, a code review, or an on-call page at 2am.

PatternWhen to Reach for It
while condition:Basic condition-driven repetition with a known exit path
while True: ... breakEvent loops, input prompts, game loops, server loops
while condition: ... else:Search loops needing to distinguish early exit from natural completion
while attempts < max and not success:Retry logic with a guaranteed maximum bound
for item in collection:Anything with a known, fixed number of iterations — not while

Next, pair this with a solid grip on Python's for loop and comprehensions — once both looping constructs are second nature, choosing between them stops being a conscious decision and starts being an instinct, which is exactly where you want to be as a developer working on real, unpredictable codebases.

Frequently Asked Questions (FAQ)