Python Break Continue Pass
In Python, the break, continue, and pass statements let you control exactly what happens inside a loop instead of always running the loop body from top to bottom on every pass. break stops a loop early, continue skips the rest of the current iteration and moves to the next one, and pass does nothing at all — it is a placeholder that keeps your code syntactically valid while you decide what to write later. Together they give you fine-grained control over for and while loops, which becomes essential once your loops need to search, filter, or handle special cases instead of blindly processing every item.
Overview: How break, continue, and pass work
break and continue only make sense inside a loop, because they change how the loop’s control flow proceeds. When the interpreter reaches a break statement, it abandons the loop immediately — no more iterations happen, and execution jumps to the first statement after the loop entirely, skipping any remaining code in the loop body and skipping the loop’s else clause (explained below). When the interpreter reaches continue, it does not exit the loop; it simply stops executing the rest of the current iteration’s body and goes back to the top of the loop to evaluate the next step — for a for loop that means fetching the next item from the iterable, and for a while loop that means re-checking the loop condition.
pass is different in kind: it is a true no-operation statement. Python’s grammar requires every indented block (the body of an if, for, while, def, class, try, and so on) to contain at least one statement — you cannot simply leave a colon followed by nothing. pass exists to satisfy that requirement when you have nothing to do yet, whether that is an empty function stub, an empty class body, or a branch of an if/elif/else chain that intentionally does nothing.
Scope: which loop does break/continue affect?
A crucial detail beginners miss: break and continue always apply to the nearest enclosing loop only. If you write a loop inside another loop (a nested loop), a break inside the inner loop exits only the inner loop — the outer loop keeps running its remaining iterations. Python has no break 2 or labeled break like some other languages; if you need to exit multiple nested loops at once, you must use a flag variable, wrap the loops in a function and return, or raise/catch an exception. The Common Mistakes section below shows this exact trap and how to fix it.
Syntax
| Statement | What it does | Where it can appear |
|---|---|---|
break |
Immediately exits the nearest enclosing for or while loop; execution resumes at the first statement after the loop. |
Inside a for or while loop body (directly, or nested inside an if/try within that loop). |
continue |
Skips the rest of the current iteration and jumps straight to the loop’s next step (the next item for for, or the condition re-check for while). |
Inside a for or while loop body. |
pass |
Does nothing. A syntactic placeholder that satisfies Python’s requirement that every block contain at least one statement. | Anywhere a statement is required: loop bodies, if/elif/else blocks, def, class, try/except, etc. |
Here is the general shape, all three keywords used together in one small loop:
for number in range(1, 11):
if number > 6:
break
if number % 2 == 0:
continue
if number == 5:
pass # placeholder: no special handling yet
print(number)
Output:
1
3
5
The loop counts from 1 to 10. Even numbers hit continue and are skipped before reaching print. When number reaches 7, the condition number > 6 is true, so break fires and the loop stops entirely — 7, 8, 9, and 10 are never even considered. The pass on 5 does nothing; it simply reserves a spot for future logic without changing behavior, so 5 still gets printed.
Examples
Example 1: break — stop searching once you find what you need
numbers = [3, 7, 12, 9, 15, 4, 22, 6]
target = None
for num in numbers:
if num % 11 == 0:
target = num
break
print(f'Checked {num}, not a multiple of 11')
if target is not None:
print(f'Found multiple of 11: {target}')
else:
print('No multiple of 11 found')
Output:
Checked 3, not a multiple of 11
Checked 7, not a multiple of 11
Checked 12, not a multiple of 11
Checked 9, not a multiple of 11
Checked 15, not a multiple of 11
Checked 4, not a multiple of 11
Found multiple of 11: 22
The loop prints a status line for every number it rejects. As soon as it reaches 22, which is divisible by 11, it stores the value and calls break. Because break exits immediately, 6 (the last item in the list) is never checked and no message is printed for it — the loop simply stops working once its job is done, which is far more efficient than scanning the whole list every time.
Example 2: continue — skip items you do not want to process
readings = [12, -5, 8, -1, 0, 19, -7, 3]
total = 0
skipped = 0
for value in readings:
if value < 0:
skipped += 1
continue
total += value
print(f'Added {value}, running total = {total}')
print(f'Final total: {total}')
print(f'Skipped {skipped} negative readings')
Output:
Added 12, running total = 12
Added 8, running total = 20
Added 0, running total = 20
Added 19, running total = 39
Added 3, running total = 42
Final total: 42
Skipped 3 negative readings
Every time value is negative, the loop increments skipped and immediately continues, which skips the total += value line and the print call for that iteration — the loop does not stop, it just moves on to the next reading. Note that 0 is not skipped, because 0 < 0 is False; only strictly negative values trigger the continue.
Example 3: pass — placeholders for unfinished code
def handle_event(event_type: str) -> None:
if event_type == 'click':
print('Handling click event')
elif event_type == 'hover':
# Not implemented yet, but syntactically required
pass
elif event_type == 'scroll':
print('Handling scroll event')
else:
pass
class FeatureFlag:
pass
events = ['click', 'hover', 'scroll', 'unknown']
for event in events:
handle_event(event)
print(FeatureFlag)
Output:
Handling click event
Handling scroll event
<class '__main__.FeatureFlag'>
The 'hover' and 'unknown' branches both use pass, so nothing prints for those events — the branches exist (perhaps to be filled in later) but currently do nothing. class FeatureFlag: pass is a very common pattern for defining an empty class quickly, often used as a marker type or a stand-in during early development; printing the class itself shows its normal representation, proving the class was defined successfully even though its body is empty.
Under the hood: the loop’s else clause
One of the more surprising features of Python is that for and while loops can have an else clause. That clause runs only if the loop finished naturally, without hitting a break. This turns out to be exactly the right tool for “search and report if not found” logic, because break is what suppresses the else block:
def is_prime(n: int) -> bool:
if n < 2:
return False
for divisor in range(2, int(n ** 0.5) + 1):
if n % divisor == 0:
break
else:
return True
return False
for candidate in [7, 8, 13, 21, 29]:
label = 'prime' if is_prime(candidate) else 'not prime'
print(f'{candidate}: {label}')
Output:
7: prime
8: not prime
13: prime
21: not prime
29: prime
Inside is_prime, the for loop tries every possible divisor up to the square root of n. If it ever finds one that divides evenly, it calls break — and because the loop was interrupted by break, the attached else block is skipped, so the function falls through to return False. If the loop runs to completion without ever breaking (no divisor was found), the else block executes and returns True. Mentally, read for...else as “else, if the loop never broke.” This pattern — loop, break when you find a match, else to handle the not-found case — avoids extra flag variables and is considered idiomatic Python once you get comfortable with it, even though many beginners never learn it exists.
Common Mistakes
Mistake 1: assuming break exits every enclosing loop
A very common bug is expecting break to stop all nested loops at once. It only stops the innermost one:
found = False
for i in range(3):
for j in range(3):
if i == j == 1:
found = True
break
print(f'Finished inner loop for i={i}')
print(f'found = {found}')
Output:
Finished inner loop for i=0
Finished inner loop for i=1
Finished inner loop for i=2
found = True
Even after the match is found at i=1, j=1, the outer loop keeps going and still runs its i=2 pass — only the inner for j loop was stopped. If the intent was to stop searching completely once a match is found, add a check after the inner loop that breaks the outer loop too:
found = False
target_i, target_j = None, None
for i in range(3):
for j in range(3):
if i == j == 1:
found = True
target_i, target_j = i, j
break
if found:
break
print(f'found = {found}, position = ({target_i}, {target_j})')
Output:
found = True, position = (1, 1)
Now the outer loop checks found right after the inner loop and breaks too, so the search truly stops as soon as a match is located. For deeply nested searches, wrapping the whole thing in a function and using return instead of a flag is usually cleaner still.
Mistake 2: using pass to silently swallow errors
Because pass is syntactically valid anywhere a statement is required, it is tempting to slap it into an except block just to make an error go away — but that hides real problems:
def parse_int(value):
try:
return int(value)
except ValueError:
pass
results = [parse_int(v) for v in ['10', 'abc', '42']]
print(results)
Output:
[10, None, 42]
This runs without crashing, but the failure for 'abc' vanishes completely — no log message, no warning, nothing to tell you or your users that something went wrong. Anyone debugging this later has no clue why a None shows up in the results. At minimum, log or print what happened:
def parse_int(value):
try:
return int(value)
except ValueError as exc:
print(f'Warning: could not parse {value!r}: {exc}')
return None
results = [parse_int(v) for v in ['10', 'abc', '42']]
print(results)
Output:
Warning: could not parse 'abc': invalid literal for int() with base 10: 'abc'
[10, None, 42]
The result is the same list, but now the failure is visible instead of silently disappearing. Reserve bare pass for cases where doing nothing really is the correct, intentional behavior — not as a shortcut to avoid thinking about error handling.
Mistake 3: using break or continue outside a loop
Both break and continue are only legal inside a loop body. Using either one anywhere else is a SyntaxError that Python catches before your program even runs:
def process(items):
if not items:
break # SyntaxError: 'break' outside loop
return items[0]
Here break is inside a function and an if statement, but there is no enclosing loop, so Python refuses to compile the module at all and raises SyntaxError: 'break' outside loop. The fix is almost always to replace the misplaced break with the statement you actually meant, such as return or raise, since those are the tools for exiting a function or signaling failure — break and continue only ever make sense as loop-control tools.
Best Practices
- Use
breakto stop searching as soon as you have your answer — it avoids wasted iterations and usually makes the intent of the code clearer than a boolean flag. - Reach for the loop’s
elseclause when your logic is “search, and do something only if nothing was found” — it removes the need for a separatefound = True/Falsevariable. - Remember that
break/continueonly affect the nearest loop; for nested loops that must exit together, use a flag checked after the inner loop, or better, extract the search into a function and usereturn. - Never use bare
passto hide an exception you have not thought through; at minimum log it, and prefer catching the narrowest exception type that applies (except ValueError, not bareexcept:). - Use
passdeliberately for genuine stubs — unfinished functions, empty classes, or an intentionally empty branch — and consider adding a short comment explaining why it is empty. - Prefer
continueover deeply nestedifblocks: an earlycontinuefor invalid or unwanted items keeps the “main path” of the loop body flat and easy to read. - Avoid overusing
breakto simulate goto-style control flow; if a loop has many possible exit points, it is often clearer as a function with severalreturnstatements.
Practice Exercises
- Exercise 1: Given the list
words = ['sky', 'ok', 'tree', 'go', 'sun', 'it'], write a loop that prints each word with three or more letters, and usescontinueto skip words with fewer than three letters. - Exercise 2: Write a loop over
range(2, 50)that finds and prints the first number divisible by both 6 and 7, then stops immediately usingbreak. (Hint: the expected answer is42.) - Exercise 3: Define an empty class named
Placeholderusingpass, then write a functiondescribe(shape)that prints a message for'circle'and'square'but does nothing (usingpass) for any other shape name. Call it with'circle','triangle', and'square'and observe which calls produce output.
Summary
breakexits the nearest enclosingfororwhileloop immediately, skipping any remaining iterations.continueskips the rest of the current iteration only, then proceeds to the loop’s next step; the loop itself keeps running.passis a no-op statement used as a placeholder wherever Python’s grammar requires a statement but you have nothing to execute yet.breakandcontinueonly ever affect the innermost loop they are written in; nested loops need a flag or areturnto exit together.- A loop’s optional
elseclause runs only when the loop completes without hittingbreak, which is ideal for search-then-report patterns. - Using
break/continueoutside any loop, or barepassto silently swallow exceptions, are both common mistakes worth watching for.
