break, continue, and pass Statements

By default, a loop runs through every single iteration, start to finish, in order. Sometimes that's not what you want — you need to stop early, skip something, or leave a spot temporarily empty. That's what python break continue pass statements are for. You've seen break and continue used briefly in the earlier loop articles in this series; this one covers all three loop control statements together, in depth, including how they interact with nesting and the else clause.

Introduction: Controlling Loop Flow

Normally, a for or while loop runs through every iteration in sequence, without deviation. Python gives you three python loop control statements for the situations where that default behavior isn't what you need:

  • break — exit the loop immediately, entirely.

  • continue — skip the rest of the current iteration, move on to the next.

  • pass — do nothing at all; a placeholder that satisfies Python's syntax requirements without actually affecting anything.

Only the first two actually change how a loop runs — pass is a fundamentally different kind of statement, covered in Section 4.

The break Statement

What it does

break immediately exits the loop it's inside, regardless of the loop's condition or how many items remain unprocessed:

numbers = [3, 7, 2, 9, 4]

for number in numbers:
    if number == 2:
        break
    print(number)
# 3
# 7

Even though 9 and 4 were still left in the list, the loop stopped the moment it hit 2, and never looked at the remaining items at all.

Practical example: searching and stopping early

This is break's most common real-world use — searching for something and stopping the moment it's found, rather than needlessly continuing through the rest of a collection:

usernames = ["alex99", "jordan_k", "sam_the_dev", "taylor22"]
target = "sam_the_dev"

for username in usernames:
    if username == target:
        print(f"Found {target}!")
        break
else:
    print(f"{target} was not found")

(The else clause here is covered in detail in Section 5 — for now, just note that break is what determines whether it runs.)

Important: break only exits the innermost loop

This catches people off guard the first time they hit it: in a nested loop, break only exits the loop it's directly inside — not any outer loops surrounding it.

for i in range(3):
    for j in range(3):
        if j == 1:
            break
        print(f"i={i}, j={j}")
# i=0, j=0
# i=1, j=0
# i=2, j=0

The break here only stops the inner j loop each time it hits j == 1 — the outer i loop keeps running normally, restarting the inner loop fresh on each pass. If you need to exit both loops at once, you generally need either a flag variable checked in the outer loop, restructuring the nested loops into a function you can return from early, or (less commonly) raising and catching an exception.

The continue Statement

What it does

continue skips the rest of the current iteration's code and jumps straight back to the loop's condition check (for while) or the next item (for for) — the loop keeps running, it just skips ahead to the next pass.

for number in range(6):
    if number % 2 == 0:
        continue
    print(number)
# 1
# 3
# 5

Every time number is even, continue skips the print() call for that specific iteration — but unlike break, the loop doesn't stop; it just moves on to check the next number.

Practical example: skipping invalid data

continue is genuinely useful when processing a collection that might contain some values you want to skip over entirely, without stopping the whole loop:

data = ["42", "", "17", "abc", "9"]

total = 0
for value in data:
    if not value.isdigit():
        continue
    total += int(value)

print(total)   # 68 — the empty string and "abc" were skipped, not counted as errors

Rather than crashing on the non-numeric entries or writing a nested conditional to wrap the rest of the loop body, continue lets you handle the "skip this one" case up front and keep the rest of the logic at a single indentation level.

break vs. continue

The core distinction, worth stating plainly: continue keeps the loop running — it just skips ahead. break ends the loop entirely — nothing after it, in that loop, ever runs again.

The pass Statement

A true no-op

pass does absolutely nothing. It's not a loop control statement in the same sense as break and continue — it exists purely to satisfy Python's syntax requirement that a block following a colon can't be empty.

if True:
    pass   # does nothing, but the block can't be left completely empty

Without pass here, Python would raise a syntax error, since if True: followed by nothing at all isn't valid — the language requires something indented underneath it.

Common uses

Placeholder for unfinished functions or classes — this is pass's most common real-world use, letting you sketch out a program's structure before filling in the actual logic:

def calculate_discount(price, percentage):
    pass   # TODO: implement this later

class ShoppingCart:
    pass   # TODO: add methods later

Both of these are completely valid Python — they define a function and a class that do nothing yet, but the code runs without error, letting you build out the rest of your program's structure and come back to fill in the details later.

Intentionally empty conditional branches — occasionally you genuinely want a branch that does nothing, often as a readable way to document "this case is deliberately ignored":

status = "pending"

if status == "error":
    print("Something went wrong")
elif status == "pending":
    pass   # intentionally no action while pending
else:
    print("Status unknown")
Why pass is fundamentally different from break and continue

This is worth being explicit about: break and continue both change the flow of a loop — they alter which iterations run or whether the loop continues at all. pass doesn't affect flow control in any way whatsoever; it's not even specific to loops. It can appear inside an if block, a function body, a class body, anywhere Python's syntax requires an indented block — and in every one of those places, it simply does nothing, letting execution continue to whatever comes next as if the block weren't there at all.

Combining Them: The for...else / while...else Pattern

What the else clause does

Both for and while loops support an else clause, and its behavior is consistent across both: the else block runs only if the loop completes without ever hitting a break. If a break does fire at any point, the else block is skipped entirely.

Why this is useful

This construct exists specifically to solve a recurring pattern cleanly: "search for something; if found, do one thing; if the search finishes without finding it, do something else" — all without needing to manually declare and check a separate found = False flag variable.

Practical combined example

Here's a single example that uses continue, break, and the else clause together — processing a batch of items where some get skipped, one triggers an early stop, and the rest complete normally if nothing does:

orders = [
    {"id": 101, "status": "shipped"},
    {"id": 102, "status": "cancelled"},
    {"id": 103, "status": "pending"},
    {"id": 104, "status": "shipped"},
]

for order in orders:
    if order["status"] == "cancelled":
        continue   # skip cancelled orders entirely, keep checking the rest

    if order["status"] == "pending":
        print(f"Order {order['id']} is still pending — stopping batch processing")
        break   # stop the whole batch as soon as a pending order is found

    print(f"Processing order {order['id']}")
else:
    print("All orders processed successfully — none were pending")

Walking through this: order 102 gets skipped via continue since it's cancelled, order 103 triggers a break because it's pending (halting the batch), and the else block — which would announce complete success — never runs, precisely because the loop was cut short by that break. If every order in the list had been either "shipped" or "cancelled", the loop would have finished naturally, and the else block's success message would have printed instead.