skip to content

questions

4

When does Python evaluate a while loop's condition, and what ends the loop?

level: juniorimportance: must knowfreq 70%

answer

  1. Ask when the test actually runs
  2. Once per pass, before the body
  3. Truthiness of the condition expression
  4. The body must make it falsy
  5. Falsy, break or exception: three exits

basics

~20 s

Python tests a while condition once before every pass and never mid-body. The loop ends only when the body changes something that makes the condition falsy, or when break, return or an exception leaves it early.

solid answer

~50 s

A `while` statement evaluates its condition expression **before each pass**, including the first, and passes the result through `bool()` — so `while queue:` loops while the container is non-empty via `__len__`. Once the body starts it runs to completion; if the condition stops being true halfway through, the loop still does not stop until the top of the next pass. That means a `while` ends in only three ways: the condition tests falsy at the top, `break` (or `return`) leaves it, or an exception propagates out. The consequence juniors get wrong is that **the body must change something the condition reads** — a counter, a container, a flag. If nothing the condition depends on changes, the loop is infinite. Python has no `do`/`while`, so a body that must run at least once is written as `while True` with an explicit `break`.

code

python · 8 lines
python
def countdown(n):
    while n > 0:
        print(n)
        n -= 1
    print("liftoff")


countdown(3)

go deeper

for a junior

Be ready to state plainly that the test runs before every pass, that a false condition means zero passes, and that you must change something in the body or the loop never ends.

for a middle

Explain the truth test behind a non-boolean condition — __bool__ then __len__ — and show why the body completes even after the condition goes false partway through.

for a senior

Demonstrate the habit of naming a loop variant: the bounded quantity every path through the body decreases. Point at the branch where progress is skipped when reviewing someone else's non-terminating loop.

for a principal

Own the guidance on when a while is the right statement at all versus a for over an iterator, and push teams toward loops whose termination argument is visible in the code rather than assumed.

### The shape of the statement A `while` statement is a condition expression plus a body. Python evaluates the condition, and if the result is truthy runs the body once; then it goes back and evaluates the condition **again**, from scratch, and repeats. This is the whole model, and almost every `while` bug is a misunderstanding of one of its two halves: *when* the test happens, and *what* makes it change. ```python n = 3 while n > 0: print(n) n -= 1 ``` The test `n > 0` runs four times here: three times truthy, once falsy. Note the first test happens *before* the first pass, so a `while` whose condition is false to begin with runs its body **zero** times — unlike a `do`/`while` in C or Java, which Python deliberately does not have. ### Truthiness, not just booleans The condition does not have to be a `bool`. Python applies the standard truth test: it calls `__bool__` on the value if the type defines one, otherwise falls back to `__len__` and treats length zero as false; an object with neither is always truthy. That is why the idiomatic drain loop is written on the container itself: ```python queue = [3, 2, 1] while queue: print(queue.pop()) ``` `while queue:` reads as "while the queue has anything in it", and stops when the list is empty. Compare `while queue is not None:` — a very different test that stays true forever once the name is bound, and a classic source of an accidental infinite loop. ### The test is at the top, and only at the top The re-evaluation happens **between** passes, never during one. If the body sets the counter past its bound halfway through, the remainder of that pass still executes: ```python i = 0 total = 0 while i < 3: i += 1 total += i # still runs on the pass where i becomes 3 print(i, total) # 3 6 ``` If you need to abandon the pass the moment something becomes true, you have to say so explicitly — test it in the body and `break` (or `return`) there. Nothing about a `while` interrupts a running body. ### The three exits A `while` loop terminates in exactly three ways: 1. **The condition evaluates falsy** at the top of a pass. This is the normal exit and the only one the condition itself controls. 2. **A `break` or `return` runs** inside the body, or the body raises. `break` leaves the loop immediately and skips the rest of the body; `return` leaves the enclosing function entirely. 3. **An exception propagates** out of the body and is not handled inside the loop. Everything else — the data running out, a timer expiring, another thread finishing — reaches the loop only if the body reads it and folds it into one of those three. ### Why the body must make progress Because the condition is re-evaluated from the same names each pass, a loop ends only if the body **changes state the condition depends on**. The classic non-terminating shapes all break that rule: ```python lines = ["a", "b"] i = 0 while i < len(lines): print(lines[i]) # forgot i += 1 -> infinite ``` - The counter is never incremented, or is incremented on only one branch of an `if`. - The condition reads a *copy* — a length captured before the loop, or a value rebound inside a nested function — so the real change is invisible to the test. - The container is refilled as fast as it is drained, so its length never reaches zero. - The test uses `!=` against a floating-point target the accumulation steps straight past, so equality never holds. A useful discipline, borrowed from program correctness, is to name the *loop variant*: some quantity that is bounded below and that **every** path through the body strictly decreases. `while queue:` has an obvious one, the length of the queue. If you cannot name a variant for a loop you are writing, you do not yet know that it terminates. ### Choosing `while` at all Use `while` when the number of passes is not known in advance and is decided by state the body produces — converging on a tolerance, consuming input until a terminator arrives, driving a state machine. When the passes are dictated by an existing sequence or a repeated call, a `for` loop is the better statement: the iterator does the advancing for you, so there is no increment to forget and no way to skip an element. Reaching for `while` to walk a list by hand is the most common needless use of the statement, and it is exactly the case where the missing increment bites.

  • If the condition becomes false halfway through the body, when does the loop actually stop?
    Not until the body finishes. Python re-evaluates the condition only at the top of the next pass, so the remainder of the current pass runs normally. If you need to abandon the pass at that exact point, test it explicitly in the body and `break` or `return` there — the condition cannot interrupt a running body.
  • What does Python do with a non-boolean while condition such as `while queue:`?
    It applies the standard truth test: `__bool__` if the type defines it, otherwise `__len__`, with length zero counting as false; an object defining neither is always truthy. So `while queue:` loops while the container is non-empty, which is the idiomatic drain loop. `while queue is not None:` is a different test that stays true forever.
  • Python has no do/while — how do you write a loop whose body must run at least once?
    Write `while True:` and put the stop test at the point in the body where it can first be evaluated, exiting with an explicit `break`. That keeps the work that produces the tested value in one place instead of duplicating it above the loop, and it is the standard Python spelling of a body-first loop.

It is a checkpoint at the top of a lap, not a referee watching the track: you are only stopped when you come back around, however early in the lap you crossed the finish line.

saying these in an interview costs you the question

  • Says the condition is monitored continuously during the body
  • Thinks a while body always runs at least once
  • Assumes the loop stops on its own when data runs out
  • Forgets to advance the counter the condition reads
  • Uses `while x is not None:` where emptiness was meant
  • Cannot name what the body changes to end the loop

context

open as a page

Why write a Python `while True:` loop with an explicit break instead of a real condition?

level: middleimportance: should knowfreq 45%

basics

~20 s

Because the stop test needs a value the body reads. A real condition forces you to duplicate that read above the loop and again at the bottom; while True with one break keeps it in one place.

open as a page

A nightly Python report job hangs in a while loop some nights — how do you diagnose it and guarantee termination?

level: seniorimportance: should knowfreq 38%

basics

~20 s

Dump a traceback from the live process to see which loop spins, then find the body path that fails to shrink what the condition reads. Fix that path, and bound the loop with a deadline and an iteration cap.

open as a page

Which Python while loops are better rewritten as for loops, and why?

level: middleimportance: nice to knowfreq 28%

basics

~20 s

Rewrite when the number of passes is dictated by an existing iterable or a repeated call rather than by state the body computes. The iterator advances for you, so there is no step to forget and no element to skip.

open as a page