Structural Pattern Matching

Structural pattern matching is Python's match/case statement (3.10+) that branches on the shape of data — the structure of a list, dict, or object — while pulling out its pieces in the same step.

Learn Structural Pattern Matching in our free Python course — an interactive lesson with runnable examples, a practice exercise and a quick reference.

Part of the free Python course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

Think of it as a far smarter if/elif chain: it can destructure sequences, mappings, and class instances, capture values, use a wildcard, and add guard conditions.

A match tests a value against each case top to bottom. A bare name captures the value; _ is the catch-all default:

Patterns can match the structure of a list or tuple and bind its parts — including a *rest to soak up the remainder:

Sequence patterns match lists and tuples by length and shape. The *rest star works just like unpacking — it captures however many items are left over.

Match dictionaries by their keys, class instances by their fields, and refine any case with an if guard:

Replace each ___ to complete the patterns so the output matches.

❌ Expecting a bare name to compare, not capture

✅ A bare name always captures. To compare against a constant, use a dotted name ( case Status.PENDING: ) or a literal ( case "pending": ).

✅ Cases run top to bottom. Put case _: (and other broad patterns) last .

✅ Structural pattern matching arrived in Python 3.10. On older versions, fall back to if/elif and isinstance .

Build a tiny interpreter that matches command lists of different shapes.

Go deeper with the official Python documentation:

Lesson complete — you match on shape now!

You can branch with match/case using literal, capture, and wildcard patterns, destructure sequences and mappings, match class instances, and refine cases with if guards.

🚀 Up next: Unpacking & Star Expressions — the destructuring tricks that power so many of these patterns.

Practice quiz

In match/case, what does a bare name pattern like 'case code:' do?

  • Compares the subject to a variable named code
  • Raises an error because names are not allowed
  • Always matches and captures the subject into code
  • Only matches if code was defined earlier

Answer: Always matches and captures the subject into code. A bare name is a capture pattern: it always matches and binds the subject to that name.

Which Python version first introduced structural pattern matching (match/case)?

  • Python 3.10
  • Python 3.8
  • Python 3.9
  • Python 3.12

Answer: Python 3.10. match/case was added in Python 3.10. Older versions raise a SyntaxError.

Given case 500 | 502 | 503:, what kind of pattern is this?

  • A guard pattern
  • A bitwise-or computation
  • A sequence pattern
  • An OR pattern matching any of the listed values

Answer: An OR pattern matching any of the listed values. The | combines alternative patterns, so the case matches 500, 502, or 503.

What does 'case [first, *rest]:' bind when matching [1, 2, 3, 4]?

The *rest star captures the remaining items, so first=1 and rest=[2, 3, 4].

What is the purpose of 'case _:' in a match statement?

  • It is a wildcard catch-all that matches anything not caught earlier
  • It matches only None
  • It captures the value into a variable named underscore
  • It marks the end of the match block

Answer: It is a wildcard catch-all that matches anything not caught earlier. The wildcard _ matches anything and does not bind a name, acting like a default branch.

Where should the catch-all 'case _:' be placed?

  • First, so it runs before other cases
  • Anywhere, order does not matter
  • Last, because cases are tested top to bottom
  • It must be the only case

Answer: Last, because cases are tested top to bottom. Cases run top to bottom; a catch-all placed first would prevent later cases from ever running.

Which case matches the dict {"type": "click", "x": 10, "y": 20}?

  • case {"type": "key", "code": code}:
  • case {"type": "click", "x": x, "y": y}:

Answer: case {"type": "click", "x": x, "y": y}:. A mapping pattern matches by keys and binds the corresponding values, so x=10 and y=20.

What does an if-guard add to a case, e.g. case {"delta": d} if d > 0:?

  • It loops the case until d > 0
  • It ignores the pattern and just checks the condition
  • It makes the case optional
  • It only matches when both the pattern matches AND the condition is true

Answer: It only matches when both the pattern matches AND the condition is true. A guard is an extra condition; the case fires only when the pattern matches and the guard is true.

For class patterns, what does 'case Point(x=0, y=0):' require?

  • Any Point instance regardless of fields
  • A Point whose x and y attributes both equal 0
  • A dict with keys x and y
  • A list of two zeros

Answer: A Point whose x and y attributes both equal 0. A class pattern matches an instance of Point and checks the given fields against the literals.

To compare a subject against a constant instead of capturing it, you should use:

  • A bare lowercase name like case pending:
  • A wildcard case _:
  • A literal or a dotted name, e.g. case "pending": or case Status.PENDING:
  • A *star pattern

Answer: A literal or a dotted name, e.g. case "pending": or case Status.PENDING:. Bare names capture; use a literal or a dotted (qualified) name to compare against a constant.