skip to content

What is the difference between `break` and `continue` in a Python loop?

level: juniorimportance: must knowfreq 82%

answer

  1. one stops, one skips
  2. how much does each abandon?
  3. which loop do they affect?
  4. innermost enclosing loop only
  5. no break inside a comprehension

basics

~20 s

break ends the innermost enclosing loop immediately and control resumes after it. continue abandons only the rest of the current pass and moves on to the next item or condition test. Neither statement touches an outer loop.

solid answer

~40 s

`break` terminates the innermost enclosing `for` or `while` loop at once: the rest of the body, the remaining items and any further condition tests are all skipped, and execution resumes at the first statement after the loop. `continue` is much weaker — it abandons only the rest of the current pass, then the loop carries on: a `for` pulls the next item from its iterator, a `while` re-evaluates its condition. Both bind to the innermost loop that encloses them, and both are a `SyntaxError` outside any loop. Idiomatically `break` means "stop the moment I have found it" and `continue` is a filter — skip the rows I do not care about and keep scanning. Comprehensions support neither, so early exit there means a real loop, `itertools.islice`, or `next()`.

code

python · 9 lines
python
codes = [200, 500, 202, 0, 204]
kept = []
for code in codes:
    if code == 0:
        break
    if code >= 500:
        continue
    kept.append(code)
print(kept)  # [200, 202]

go deeper

for a junior

Be ready to state both in one sentence and then trace a short loop out loud, saying exactly which items still reach the body and what the loop variable holds once the loop ends.

for a middle

Explain that both bind to the innermost enclosing loop, that continue sends a while straight back to its condition test while a for pulls the next item, and that comprehensions support neither.

for a senior

In review, judge whether an early break genuinely expresses intent or hides a search that should be a next() over a generator, and whether stacked continue guards have buried the condition that actually matters.

for a principal

Own the convention: when guard-style continue is preferred over deeper nesting, and when a hand-rolled scanning loop should instead become a named, tested helper that returns its find.

Both statements alter the normal flow of a loop, but they differ in how much they abandon. ### `break` — leave the loop When `break` executes, the innermost enclosing `for` or `while` loop stops immediately. The remainder of the body is skipped, no further item is pulled from the iterator, no further condition test happens, and execution resumes at the first statement following the loop. Nothing else is unwound: the function keeps running, and the loop variable keeps whatever value it held when the `break` fired, which is exactly why the "scan until found, then use the variable" idiom works. The iterator is simply dropped, not exhausted or closed. If you were looping over a generator object you still hold a reference to, it stays suspended at the point it yielded, and a later loop over the same object resumes from there. That is a genuine gotcha when a helper hands the same iterator to two consumers. ### `continue` — leave the pass `continue` abandons only the current iteration. Everything below it in the body is skipped for that pass, and control jumps back to the top of the loop. What happens next depends on the loop kind: a `for` asks its iterator for the next item and runs the body again (or ends if the iterator is exhausted), while a `while` re-evaluates its condition expression and runs the body again only if it is still true. The most common misreading is that `continue` restarts the loop from the beginning of the sequence, or that it skips the *next* item. It does neither. It is a jump to the bottom of the current pass, nothing more. ### They bind to the innermost loop Neither statement takes an argument, and Python has no loop labels. In two nested loops, a `break` written in the inner body ends the inner loop only — the outer loop then continues with its next item, usually giving the very bug where a search "keeps running after it found the answer". Escaping several levels at once is a separate problem with its own idioms. Both statements are only legal lexically inside a loop in the same code object. Writing either at module level, or in a function body that happens to be defined inside a loop, is a `SyntaxError` at compile time rather than a runtime failure. ### Guard style A `continue` used as a guard is often the cleanest way to keep a loop body flat: filter out the passes you do not care about at the top, then write the real work at one indentation level. The alternative — wrapping the whole body in an `if` — pushes everything a level deeper and, in a long body, hides the condition far from the code it governs. Overusing it has the opposite effect: five `continue` guards in a row make the surviving cases hard to name, and that is usually a sign the filtering belongs in a comprehension or a generator that the loop then consumes. ### Comprehensions have neither `break` and `continue` are statements, and a comprehension is an expression, so `[x for x in items if break]` does not parse — it is a `SyntaxError`. A comprehension's `if` clause *filters*, which covers the `continue` case, but there is no way to stop it early. When you need early exit, the options are to write an ordinary `for` loop with `break`, to build a generator expression and take a prefix with `itertools.islice`, or to grab the first match with `next(gen, default)`. The last two keep the work lazy, so items past the stopping point are never computed at all. ### Interaction with the rest of the loop `break` and `continue` inside a `try` block are legal and cooperate with cleanup: the attached `finally` clause runs on the way out before the jump takes effect. Inside a `with` block, the context manager's `__exit__` runs likewise, so an early exit never leaks the managed resource. Neither statement is a substitute for `return`: `break` leaves the loop and keeps executing the function, while `return` leaves the function entirely. ### What an interviewer is checking At junior level this is a trace-by-hand question. Given a short loop with both statements, an interviewer wants you to say precisely which items reach the body, which value the loop variable holds afterwards, and where execution lands when the loop ends. Getting `continue`'s destination right — the *next* pass, not a restart — is the whole point.

  • Where does execution resume after a `break` in a Python `for` loop?
    At the first statement after the loop body. The remaining items are never requested, and the loop variable keeps the value it had when the `break` fired, which is what makes the scan-then-use idiom work. The iterator is dropped rather than exhausted, so a generator object you still hold a reference to stays suspended at its last `yield` and a later loop over it resumes from there.
  • How do you stop early when the code is a comprehension rather than a loop?
    A comprehension has no `break` — writing one is a `SyntaxError`, because `break` is a statement and a comprehension is an expression. Rewrite it as a `for` loop with a `break`, or keep it lazy: build a generator expression and take a prefix with `itertools.islice`, or grab the first match with `next(gen, default)`. Both stop pulling items as soon as you have enough.
  • Is `continue` allowed inside a `try` block?
    Yes. A `continue` in the `try` or `except` suite runs the attached `finally` clause on the way out and then proceeds to the next pass. `continue` inside the `finally` block itself was a `SyntaxError` before Python 3.8; it is legal now, but Python 3.14 emits a `SyntaxWarning` for it, because leaving a `finally` that way silently discards an exception still in flight.

saying these in an interview costs you the question

  • Says continue restarts the loop from the first item
  • Thinks one break leaves every enclosing loop
  • Believes continue also skips the following item
  • Confuses continue with pass, which does nothing
  • Claims break exits the function like return
  • Expects break to work inside a list comprehension

context