for/while…else

An else clause on a loop runs only if the loop finished without hitting a break — genuinely surprising the first time you see it.

                for item in iterable:
    ...
else:
    ...

              

Purpose

Both for and while accept an optional else clause. Despite the keyword, it has nothing to do with if/else — it means “run this if the loop completed normally,” i.e. ran out of items (for for) or its condition became false (for while) without a break ending it early.

Example

def find_first_negative(numbers: list[int]) -> int | None:
    for number in numbers:
        if number < 0:
            found = number
            break
    else:
        found = None
    return found
find_first_negative([4, 7, -2, 9])  ->  -2   (break ran; else skipped)
find_first_negative([4, 7, 2, 9])   ->  None (loop finished; else ran)

Behavior notes

  • The else block runs exactly when the loop’s own break did not run — that includes the ordinary case of the loop finishing all its iterations, and also the edge case of an empty iterable (a for loop over [] never runs its body, never hits break, and so its else still runs).
  • This is the classic idiom for a “search, then handle not-found” pattern without a separate found-flag variable — precisely what the example above does.
  • An exception raised inside the loop body skips the else clause entirely, the same way it would skip any other code after the loop.

Common mistakes

  • Reading else here as “if the loop’s condition was ever false” (an if/else mental model) — that’s not what it checks. It checks whether break ran, nothing else.
  • Adding a loop’s else clause out of habit when nothing in the loop body ever calls break — in that case the else block always runs and is equivalent to just writing the same code unindented, immediately after the loop.

Implementation notes

This is a language-level control-flow rule, identical across every conforming Python implementation — not a CPython-specific behavior.

Taught in these lessons