Loop Control: break, continue, and Loop else

Updated

September 7, 2026

Loop Control: break, continue, and Loop else

After reading this chapter, you will master loop execution interruption using break and continue, eliminate boolean search flags using the loop else clause, break out of nested loop structures cleanly, and handle pipeline filtering without nested conditional blocks.

Mental model

Python provides three control keywords that alter standard loop iteration:

Loop Control Keywords:
  1. continue ──▶ Immediately skips the remaining statements in the current iteration;
                  jumps directly to the next iteration evaluation.
  2. break    ──▶ Immediately aborts the entire loop;
                  jumps to the first statement outside the loop.
  3. else     ──▶ Executes IF AND ONLY IF the loop finished all iterations
                  without hitting an explicit break statement!
The Loop 'else' Contract:
  for item in sequence:
      if item == target:
          break ─────────────────────────┐ (Bypasses loop 'else'!)
  else:                                  │
      # Runs ONLY if target was NOT found│
      print("Item missing!")             │
                                         ▼
  [ Resume Outer Execution ] ◀───────────┘

Minimal example

Save as loop_control_statements.py:

# loop_control_statements.py
def inspect_packet_batch(packets: list[dict[str, str | int]]) -> None:
    print(f"Inspecting batch of {len(packets)} network packets...")

    for pkt in packets:
        # 1. 'continue' skips empty or malformed packets
        if pkt.get("size", 0) <= 0:
            print(f"  [Skip] Packet {pkt.get('id')} has 0 bytes. Continuing.")
            continue

        # 2. 'break' immediately terminates loop on critical security violation
        if pkt.get("flags") == "MALICIOUS":
            print(f"  [SECURITY ALERT] Malicious payload detected on ID {pkt['id']}! Terminating inspection immediately.")
            break
        
        print(f"  [OK] Packet {pkt['id']} verified ({pkt['size']} bytes).")
    else:
        # 3. Loop 'else' executes ONLY if loop completed without hitting 'break'
        print("  [SUCCESS] All packets verified clean. Batch approved for forwarding.")

def main() -> None:
    # Test clean batch
    clean_batch = [
        {"id": 101, "size": 64, "flags": "SYN"},
        {"id": 102, "size": 0, "flags": "ACK"},  # Skipped via continue
        {"id": 103, "size": 128, "flags": "ACK"},
    ]
    print("--- Test 1: Clean Batch ---")
    inspect_packet_batch(clean_batch)

    # Test malicious batch
    dirty_batch = [
        {"id": 201, "size": 64, "flags": "SYN"},
        {"id": 202, "size": 512, "flags": "MALICIOUS"}, # Aborted via break
        {"id": 203, "size": 64, "flags": "ACK"},
    ]
    print("\n--- Test 2: Dirty Batch ---")
    inspect_packet_batch(dirty_batch)

if __name__ == "__main__":
    main()

Run via uv run python loop_control_statements.py:

--- Test 1: Clean Batch ---
Inspecting batch of 3 network packets...
  [OK] Packet 101 verified (64 bytes).
  [Skip] Packet 102 has 0 bytes. Continuing.
  [OK] Packet 103 verified (128 bytes).
  [SUCCESS] All packets verified clean. Batch approved for forwarding.

--- Test 2: Dirty Batch ---
Inspecting batch of 3 network packets...
  [OK] Packet 201 verified (64 bytes).
  [SECURITY ALERT] Malicious payload detected on ID 202! Terminating inspection immediately.

Worked examples

Case 1: Search and Validate Without Boolean Flags (for ... else)

In languages like C or Java, checking whether a list contains an item matching specific criteria requires setting a boolean flag (found = False). Python’s loop else eliminates this boilerplate:

# target_finder_clean.py
def find_available_worker(workers: list[dict[str, str | int]]) -> None:
    # Search for an idle worker with CPU load under 20%
    for w in workers:
        if w["status"] == "IDLE" and w["cpu_pct"] < 20:
            print(f"Dispatching task to worker: {w['name']} (CPU: {w['cpu_pct']}%)")
            break
    else:
        # Executes only if no worker matched
        print("CAPACITY ALERT: No available idle worker found across cluster!")

if __name__ == "__main__":
    cluster = [
        {"name": "worker-01", "status": "BUSY", "cpu_pct": 85},
        {"name": "worker-02", "status": "IDLE", "cpu_pct": 95},
        {"name": "worker-03", "status": "BUSY", "cpu_pct": 40},
    ]
    find_available_worker(cluster)

Run:

uv run python target_finder_clean.py

Output:

CAPACITY ALERT: No available idle worker found across cluster!

Case 2: Breaking Out of Nested Loops

A break statement only terminates the innermost loop. To exit multiple nested loops simultaneously without clumsy flag variables, encapsulate the nested loops in a function and use return:

# nested_loop_exit.py
def locate_corrupted_block(matrix: list[list[int]]) -> tuple[int, int] | None:
    """Scan a 2D matrix and return (row, col) coordinates of first negative value."""
    for row_idx, row in enumerate(matrix):
        for col_idx, value in enumerate(row):
            if value < 0:
                # 'return' instantly exits BOTH loops cleanly!
                return (row_idx, col_idx)
    return None

if __name__ == "__main__":
    storage_grid = [
        [100, 200, 300],
        [400, -999, 600],  # Corrupted block at row 1, col 1
        [700, 800, 900],
    ]
    coord = locate_corrupted_block(storage_grid)
    print(f"Corrupted block coordinates: {coord}")

Run:

uv run python nested_loop_exit.py

Output:

Corrupted block coordinates: (1, 1)

Pitfalls

Pitfall 1: Assuming break Exits All Nested Loops

Calling break inside an inner loop returns control to the outer loop, not the code outside the outer loop:

for outer in range(3):
    for inner in range(3):
        if inner == 1:
            break  # Exits 'inner' loop only! 'outer' continues iterating!

To exit both, encapsulate the nested loops inside a function and use return, or use a custom exception.

Pitfall 2: Confusing Loop else with if else

A loop else does not mean “run if the loop didn’t execute”. If a loop iterates over an empty list (for x in []:), it completes 0 iterations without hitting break, so the else block does execute! Think of loop else as “no-break”.


Exercises

  1. Write a prime number checker using for ... in range(2, n): ... break else: to determine whether \(n\) is prime without boolean flags.
  2. Given a list of log entries, use continue to filter out all entries that do not contain "ALERT" or "CRITICAL".
  3. Demonstrate that iterating over an empty list for item in []: break else: print("RUN") executes the else block.
  4. Implement a function that scans a 3D tensor and uses return to break out of all three nested loops when a NaN value is encountered.

Further reading

  • Python Language Reference: The break and continue statements.
  • Raymond Hettinger: Transforming Code into Beautiful, Idiomatic Python (The for-else idiom).