Conditionals, Loops, Loop Control & match-case

Control flow in Python determines how the VM branches execution paths. Beyond standard if/elif/else conditionals and while/for loops, modern Python features Structural Pattern Matching (match/case) introduced in PEP 634 and the often misunderstood Loop else clause.

This chapter details CPython bytecode branching, Structural Pattern Matching AST destructuring, and loop control semantics.


1. Structural Pattern Matching Mechanics (match/case)

match/case is not a simple C-style switch statement that evaluates integer values. It is a full destructuring pattern engine that matches values, types, and sequence structures at runtime:

Structural Pattern Matching Execution Pipeline:

[ Subject Value (e.g. command = ["MOVE", 10, 20]) ]
                         |
                         v
[ Case 1: Sequence Destructuring match ["MOVE", x, y] ]
     β”œβ”€ Type Check: Is subject a Sequence? (Yes)
     β”œβ”€ Length Check: Does len == 3? (Yes)
     β”œβ”€ Constant Match: Does subject[0] == "MOVE"? (Yes)
     └─ Variable Binding: Bind x = 10, y = 20
                         |
                         v
[ Match Succeeded! Execute Case Block ]

Pattern Matching Types:

  1. Literal Pattern: case 200: matches exact values.
  2. Sequence Pattern: case [x, y, *rest]: matches lists/tuples and captures remaining items.
  3. Mapping Pattern: case {"action": "build", "id": item_id}: matches dictionary key structures.
  4. Class Pattern: case Point(x=x, y=y): checks isinstance() and attributes via __match_args__.
  5. Guard Expressions: case x if x > 0: adds boolean conditional guards to matching patterns.

2. Loop else Clause Execution Rules

Python allows adding an else block to for and while loops. The execution rule is strict:

The loop else block executes IF AND ONLY IF the loop completes naturally without encountering a break statement.

def find_target(items, target):
    for item in items:
        if item == target:
            print("Found target!")
            break  # Exits loop IMMEDIATELY -> 'else' block is SKIPPED!
    else:
        # Executes ONLY if the loop ran to completion without hitting 'break'
        print("Target not found in sequence.")

3. Bytecode Branching (POP_JUMP_IF_FALSE)

At the bytecode level, if/else statements compile into comparison instructions followed by conditional jump opcodes:

  • COMPARE_OP: Compares stack values.
  • POP_JUMP_IF_FALSE (target_offset): Pops the comparison boolean off the evaluation stack. If False, jumps execution directly to the specified bytecode instruction offset.

4. Production Trade-offs & Style Boundaries

  • match/case vs if/elif: Use match/case when destructuring complex nested JSON or class objects. Avoid match/case for simple integer/string equality checks where standard dictionary mapping lookups (handler_dict[cmd]()) are cleaner.
  • Nested Loops: Deeply nested loops with multiple break flags increase cyclomatic complexity. Refactor nested searches into helper generator functions using return.
Display Options
Appearance
Text Size
100%