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 break to 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 else clause when your logic is “search, and do something only if nothing was found” — it removes the need for a separate found = True/False variable.
  • Remember that break/continue only 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 use return.
  • Never use bare pass to hide an exception you have not thought through; at minimum log it, and prefer catching the narrowest exception type that applies (except ValueError, not bare except:).
  • Use pass deliberately for genuine stubs — unfinished functions, empty classes, or an intentionally empty branch — and consider adding a short comment explaining why it is empty.
  • Prefer continue over deeply nested if blocks: an early continue for invalid or unwanted items keeps the “main path” of the loop body flat and easy to read.
  • Avoid overusing break to simulate goto-style control flow; if a loop has many possible exit points, it is often clearer as a function with several return statements.

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 uses continue to 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 using break. (Hint: the expected answer is 42.)
  • Exercise 3: Define an empty class named Placeholder using pass, then write a function describe(shape) that prints a message for 'circle' and 'square' but does nothing (using pass) for any other shape name. Call it with 'circle', 'triangle', and 'square' and observe which calls produce output.

Summary

  • break exits the nearest enclosing for or while loop immediately, skipping any remaining iterations.
  • continue skips the rest of the current iteration only, then proceeds to the loop’s next step; the loop itself keeps running.
  • pass is a no-op statement used as a placeholder wherever Python’s grammar requires a statement but you have nothing to execute yet.
  • break and continue only ever affect the innermost loop they are written in; nested loops need a flag or a return to exit together.
  • A loop’s optional else clause runs only when the loop completes without hitting break, which is ideal for search-then-report patterns.
  • Using break/continue outside any loop, or bare pass to silently swallow exceptions, are both common mistakes worth watching for.