# 37. Pattern Matching

# 37. Pattern Matching

Pattern matching is Python’s structural matching system. It is implemented by the `match` statement and `case` clauses.

```python
match value:
    case 0:
        result = "zero"
    case [x, y]:
        result = x + y
    case {"name": name}:
        result = name
    case _:
        result = None
```

Pattern matching is not a switch statement over constants only. It can inspect structure, bind names, test classes, match sequences, match mappings, apply guards, and select a case based on runtime shape.

At the CPython level, pattern matching is compiled into ordinary bytecode plus specialized matching instructions. The interpreter evaluates the subject, tries each case in order, binds names for a successful match, and jumps to the selected body.

## 37.1 The `match` Statement

A `match` statement has one subject expression and one or more cases.

```python
match subject:
    case pattern:
        body
    case pattern if guard:
        body
    case _:
        body
```

The subject expression is evaluated once.

```python
match compute():
    case 1:
        ...
    case 2:
        ...
```

`compute()` runs one time. The result is then tested against the cases from top to bottom.

Conceptually:

```text
subject = compute()

try case 1
if match succeeds:
    execute case 1 body
else:
    try case 2
```

Only the first matching case body runs.

## 37.2 Patterns vs Expressions

Patterns look like expressions, but they follow different rules.

```python
match value:
    case x:
        ...
```

This does not compare `value` with an existing variable `x`. It captures the subject into a new name `x`.

A capture pattern always succeeds.

```python
case x:
```

means:

```text
bind x = subject
match succeeds
```

To compare against a named constant, use a dotted name:

```python
case Color.RED:
```

or use a guard:

```python
case x if x == expected:
```

This distinction matters because pattern matching has its own syntax and binding rules.

## 37.3 Case Order

Cases are tried in order.

```python
match value:
    case int():
        result = "integer"
    case bool():
        result = "boolean"
```

This is a bad order because `bool` is a subclass of `int`.

```python
isinstance(True, int)
```

is true.

So `True` matches `int()` before reaching `bool()`.

Better:

```python
match value:
    case bool():
        result = "boolean"
    case int():
        result = "integer"
```

Pattern matching uses runtime type and structure. More specific cases should usually appear before more general cases.

## 37.4 Wildcard Pattern

The wildcard pattern `_` matches anything and binds nothing.

```python
match value:
    case 0:
        result = "zero"
    case _:
        result = "other"
```

The `_` pattern is commonly used as the final fallback.

It differs from a normal capture name:

```python
case name:
```

This binds `name`.

```python
case _:
```

This does not bind `_` as a new local for the match result.

## 37.5 Literal Patterns

Literal patterns match values such as numbers, strings, bytes, booleans, and `None`.

```python
match value:
    case 0:
        result = "zero"
    case "ok":
        result = "success"
    case None:
        result = "missing"
```

For most literals, matching uses equality semantics.

```text
subject == literal
```

For singleton constants such as `None`, `True`, and `False`, matching uses identity-style singleton semantics.

Literal patterns are useful for tags, small states, and protocol markers.

## 37.6 Capture Patterns

A capture pattern binds a name.

```python
match value:
    case x:
        result = x
```

This always matches.

Capture patterns are useful inside larger patterns:

```python
match point:
    case [x, y]:
        result = x + y
```

Here, `[x, y]` is a sequence pattern. The names `x` and `y` capture elements.

After a successful match, bound names are available in the case body.

```python
match value:
    case [x, y]:
        print(x, y)
```

If the match fails, bindings from that failed pattern must not leak in a way user code can rely on.

## 37.7 Value Patterns

A value pattern compares the subject with a value referenced by a dotted name.

```python
match color:
    case Color.RED:
        handle_red()
    case Color.BLUE:
        handle_blue()
```

The dotted name is evaluated and compared with the subject.

This is different from:

```python
case RED:
```

which captures into a name called `RED`.

For constants, use dotted names, enums, or guards.

```python
class Status:
    OK = "ok"
    ERROR = "error"

match status:
    case Status.OK:
        ...
```

## 37.8 OR Patterns

An OR pattern matches if any alternative matches.

```python
match value:
    case 0 | 1 | 2:
        result = "small"
```

All alternatives must bind the same set of names.

Valid:

```python
match value:
    case [x] | (x,):
        result = x
```

Invalid in principle:

```python
case [x] | [x, y]:
```

because the first alternative binds `x`, while the second binds `x` and `y`.

The compiler checks name-binding consistency for OR patterns.

## 37.9 AS Patterns

An AS pattern binds the whole matched value while also matching a subpattern.

```python
match value:
    case [x, y] as pair:
        print(x, y, pair)
```

If the subject matches `[x, y]`, then:

```text
x = first element
y = second element
pair = whole subject
```

This is useful when you need both destructured fields and the original value.

## 37.10 Guards

A guard is an `if` condition attached to a case.

```python
match value:
    case [x, y] if x < y:
        result = "ascending"
```

The pattern is matched first. If it succeeds, the guard is evaluated.

Conceptually:

```text
if subject matches [x, y]:
    if x < y:
        execute body
    else:
        try next case
```

Guards can run arbitrary Python code. They can raise exceptions, call functions, mutate state, or depend on captured names.

If a guard evaluates to false, the case is treated as not selected, and matching continues with the next case.

## 37.11 Sequence Patterns

A sequence pattern matches sequence-like objects.

```python
match value:
    case [x, y]:
        result = x + y
```

This matches sequences of length two.

Examples that may match:

```python
[1, 2]
(1, 2)
```

Strings and bytes are not treated as sequences for this purpose, even though they are sequence-like in other contexts.

Sequence matching needs to check:

```text
is the subject a sequence pattern candidate
does it have the required length
extract elements
match nested subpatterns
bind names
```

## 37.12 Starred Sequence Patterns

A starred pattern captures a variable-length middle section.

```python
match value:
    case [first, *middle, last]:
        ...
```

For:

```python
value = [1, 2, 3, 4]
```

the bindings are:

```text
first = 1
middle = [2, 3]
last = 4
```

The starred capture receives a list.

The pattern requires at least enough elements for the non-starred positions.

```python
case [first, *middle, last]:
```

requires at least two elements.

## 37.13 Mapping Patterns

A mapping pattern matches mapping-like objects.

```python
match value:
    case {"name": name, "age": age}:
        ...
```

This checks that the subject has the required keys.

For:

```python
value = {"name": "Ada", "age": 37, "city": "London"}
```

the pattern matches and binds:

```text
name = "Ada"
age = 37
```

Extra keys are allowed unless the pattern uses stricter logic outside the pattern, such as a guard.

Mapping patterns can also capture remaining items:

```python
match value:
    case {"name": name, **rest}:
        ...
```

Then `rest` receives a dictionary of unmatched keys.

## 37.14 Class Patterns

Class patterns match objects by type and attributes.

```python
match value:
    case Point(x, y):
        ...
```

This checks whether `value` is an instance of `Point`, then extracts fields.

The meaning of positional fields is controlled by `Point.__match_args__`.

Example:

```python
class Point:
    __match_args__ = ("x", "y")

    def __init__(self, x, y):
        self.x = x
        self.y = y
```

Then:

```python
match p:
    case Point(x, y):
        ...
```

is conceptually similar to:

```text
isinstance(p, Point)
x = p.x
y = p.y
```

with pattern-matching semantics and failure behavior.

## 37.15 Keyword Class Patterns

Class patterns can name attributes explicitly.

```python
match value:
    case Point(x=0, y=y):
        ...
```

This matches a `Point` whose `x` attribute matches `0`, and binds the `y` attribute.

Keyword class patterns do not depend on `__match_args__` for those attributes.

Conceptually:

```text
check isinstance(value, Point)
get value.x and match against 0
get value.y and bind y
```

Attribute lookup can execute code, so class patterns can have side effects if properties or custom attribute access are involved.

## 37.16 `__match_args__`

`__match_args__` maps positional class pattern fields to attribute names.

```python
class Point:
    __match_args__ = ("x", "y")
```

This allows:

```python
case Point(a, b):
```

to mean:

```python
case Point(x=a, y=b):
```

For dataclasses and named tuples, Python often provides useful `__match_args__` automatically.

If `__match_args__` is missing, empty, or incompatible, positional class patterns may fail or raise errors depending on the pattern form.

## 37.17 Nested Patterns

Patterns can nest.

```python
match value:
    case {"point": Point(x, y), "label": label}:
        ...
```

This checks:

```text
subject is a mapping
subject has key "point"
subject has key "label"
subject["point"] is a Point
extract Point.x and Point.y
bind label
```

Nested patterns are compiled into a sequence of tests and extraction operations.

If any nested part fails, the whole case fails and matching continues with the next case.

## 37.18 Name Binding

Names bound in a successful case become local variables in the surrounding scope.

```python
def f(value):
    match value:
        case [x, y]:
            return x + y
        case _:
            return 0
```

The compiler treats `x` and `y` as local names in `f`.

This can affect scope analysis. A name captured by a pattern is a binding occurrence, similar to assignment.

Example:

```python
def f(value):
    match value:
        case x:
            return x
```

Here, `x` is local to `f`.

## 37.19 Failed Match Bindings

A failed pattern should not be used as a source of stable bindings.

Example:

```python
match value:
    case [x, 0]:
        ...
    case _:
        ...
```

If the first case fails after binding part of the structure, CPython must avoid exposing partial bindings as successful results.

The language semantics do not let you rely on names bound during failed matches.

Compiler and interpreter code must preserve this rule.

## 37.20 Pattern Matching Bytecode

Pattern matching compiles into bytecode.

A simple example:

```python
def f(value):
    match value:
        case [x, y]:
            return x + y
        case _:
            return 0
```

Conceptual bytecode structure:

```text
load subject

try sequence case:
    check sequence
    check length 2
    unpack into x, y
    execute body
    return

fallback:
    return 0
```

CPython includes pattern-specific opcodes for common checks, such as sequence matching, mapping matching, key extraction, and class matching. The exact opcode names and layout can change between versions.

## 37.21 Subject Duplication

The subject must often remain available while trying multiple cases.

```python
match value:
    case [x]:
        ...
    case {"x": x}:
        ...
    case _:
        ...
```

If the first case fails, the second case still needs the original subject.

The compiler emits stack operations to duplicate, preserve, or discard the subject as needed.

Conceptually:

```text
subject on stack
try case 1
    if fail, restore subject
try case 2
    if fail, restore subject
fallback
```

Correct stack discipline is important because pattern matching has many failure paths.

## 37.22 Failure Paths

A case can fail at many points:

```text
wrong type
wrong sequence length
missing mapping key
class check fails
attribute extraction fails with AttributeError
nested subpattern fails
OR alternative fails
guard is false
```

Some failures are normal non-matches. Others are real exceptions.

Pattern matching must distinguish:

```text
normal pattern failure
real runtime exception
```

For example, a missing mapping key means the mapping pattern does not match.

But a property getter that raises `RuntimeError` during a class pattern should propagate the exception.

## 37.23 Guards and Exceptions

A guard is ordinary Python code.

```python
match value:
    case x if check(x):
        ...
```

If `check(x)` raises, the exception propagates. The interpreter does not treat it as a failed match.

Conceptually:

```text
pattern succeeds
evaluate guard
    returns true: select case
    returns false: try next case
    raises: propagate exception
```

This makes guards powerful but also effectful.

## 37.24 Mapping Key Lookup

Mapping patterns use key lookup. A pattern such as:

```python
case {"name": name}:
```

checks whether the subject contains the key `"name"` and extracts its value.

The implementation must avoid accidentally invoking behavior that changes semantics compared with mapping-pattern rules.

The important source-level behavior is:

```text
required keys must exist
their values must match subpatterns
extra keys are allowed
```

If `**rest` is present, unmatched key-value pairs are copied into a new dictionary.

## 37.25 Class Pattern Attribute Lookup

Class patterns can perform attribute lookup.

```python
case Point(x=x, y=y):
```

This may call:

```text
Point-related descriptors
properties
__getattribute__
__getattr__
```

If attribute access raises `AttributeError`, the class pattern can fail as a non-match for that attribute. Other exceptions propagate.

Example:

```python
class C:
    @property
    def x(self):
        raise RuntimeError("bad")

match C():
    case C(x=x):
        ...
```

This propagates `RuntimeError`.

## 37.26 Pattern Matching and Descriptors

Because class patterns use attribute access, descriptors can participate.

```python
class C:
    @property
    def x(self):
        return 10

match C():
    case C(x=10):
        result = "matched"
```

The property getter runs during matching.

This means pattern matching can trigger user code. It is not always a passive structural inspection.

## 37.27 Pattern Matching and Dataclasses

Dataclasses work naturally with class patterns.

```python
from dataclasses import dataclass

@dataclass
class Point:
    x: int
    y: int

def f(p):
    match p:
        case Point(0, y):
            return y
        case Point(x, y):
            return x + y
```

Dataclasses typically provide `__match_args__` based on fields, so positional class patterns work.

Conceptually:

```text
Point(0, y)
    matches Point instance
    checks x == 0
    binds y from p.y
```

## 37.28 Pattern Matching and Enums

Enums are often used with value patterns.

```python
from enum import Enum

class TokenKind(Enum):
    NAME = 1
    NUMBER = 2

match kind:
    case TokenKind.NAME:
        ...
    case TokenKind.NUMBER:
        ...
```

The dotted names are value patterns, so they compare against existing enum members.

Do not write:

```python
case NAME:
```

unless you intend to capture a new variable.

## 37.29 Pattern Matching and ASTs

Pattern matching is useful for tree-like structures.

```python
match node:
    case BinOp(left, "+", right):
        ...
    case Literal(value):
        ...
```

A compiler or interpreter can use class patterns to inspect node types.

Example:

```python
@dataclass
class Literal:
    value: object

@dataclass
class BinOp:
    left: object
    op: str
    right: object
```

Then:

```python
match node:
    case BinOp(Literal(a), "+", Literal(b)):
        return Literal(a + b)
```

This expresses structural decomposition directly.

## 37.30 Pattern Matching and Bytecode Stack

Pattern matching uses the frame value stack like other bytecode.

The subject, intermediate extracted values, comparison results, and preserved fallback values may live on the stack.

A sequence pattern:

```python
case [x, y]:
```

conceptually does:

```text
subject
check sequence
check length
unpack two elements
store x
store y
execute body
```

If it fails, temporary values are popped and the next case starts from a clean stack shape.

## 37.31 Compiler Responsibilities

The compiler must generate bytecode that preserves several invariants:

```text
subject evaluated once
cases tried in order
successful pattern bindings visible in body
failed pattern bindings not relied on
guards evaluated after binding
guards can access bound names
stack shape valid at every jump
exceptions propagate correctly
only first successful case runs
```

Pattern matching is therefore both a language feature and a compiler feature.

## 37.32 Runtime Responsibilities

At runtime, CPython must perform:

```text
type checks
sequence checks
mapping checks
class checks
attribute extraction
key extraction
equality checks
binding
guard evaluation
failure jumps
exception propagation
```

Some of these operations are generic Python operations and can call user code.

For example:

```python
case SomeClass(x=x):
```

may execute descriptor logic for `x`.

```python
case 10:
```

may use equality comparison.

Pattern matching must remain correct under Python’s dynamic object model.

## 37.33 Pattern Matching and Equality

Literal and value patterns can use equality.

```python
case 10:
```

matches if the subject equals `10`.

For user-defined objects, equality can call `__eq__`.

```python
class C:
    def __eq__(self, other):
        print("compare")
        return True

match C():
    case 10:
        print("matched")
```

This can execute user code.

If equality raises an exception, the exception propagates.

## 37.34 Pattern Matching and Performance

Pattern matching can be clear, but it is not magic. It still performs runtime checks.

Costs may include:

```text
type checks
length checks
mapping lookups
attribute lookups
equality comparisons
temporary allocations
guard execution
bytecode branches
```

A simple `if` chain may be faster for very small scalar cases.

Pattern matching is most useful when structure matters:

```text
nested data
AST nodes
protocol messages
token streams
configuration shapes
command parsing
event dispatch
```

Use it where it improves clarity.

## 37.35 Pattern Matching vs `if/elif`

This:

```python
match value:
    case 0:
        ...
    case 1:
        ...
```

can be similar to:

```python
if value == 0:
    ...
elif value == 1:
    ...
```

But pattern matching goes further:

```python
match value:
    case {"type": "user", "name": name}:
        ...
    case ["move", x, y]:
        ...
    case Point(x=0, y=y):
        ...
```

It combines type tests, shape tests, unpacking, and binding.

## 37.36 Pattern Matching vs Destructuring Assignment

Destructuring assignment requires the shape to match or raises.

```python
x, y = value
```

If `value` does not have exactly two items, it raises.

Pattern matching tests shape and can fall through.

```python
match value:
    case [x, y]:
        ...
    case _:
        ...
```

Failure to match `[x, y]` simply tries the next case.

So pattern matching is conditional destructuring.

## 37.37 Pattern Matching and Scope

Names captured in patterns are local bindings.

```python
def f(value):
    match value:
        case x:
            return x
```

The compiler treats `x` as local to `f`.

This can surprise users expecting a comparison to an outer variable.

```python
expected = 10

def f(value):
    match value:
        case expected:
            return True
```

This captures into a local name `expected`. It does not compare to the outer `expected`.

Use:

```python
def f(value):
    match value:
        case x if x == expected:
            return True
```

or use a dotted constant.

## 37.38 Pattern Matching and Unreachable Cases

A capture pattern catches everything.

```python
match value:
    case x:
        ...
    case 0:
        ...
```

The second case is unreachable.

Similarly:

```python
case _:
```

as a non-final case makes later cases unreachable.

The compiler detects some irrefutable patterns in invalid positions.

An irrefutable pattern is one that always matches, such as:

```text
_
x
object()
```

in many contexts.

## 37.39 Pattern Matching and `object()`

A class pattern with no arguments can match any instance of that class.

```python
case object():
```

Since nearly all normal objects are instances of `object`, this is broadly matching.

It is different from:

```python
case object:
```

which is a capture pattern named `object`, unless syntax resolves differently through context. Avoid ambiguous names in patterns.

## 37.40 Pattern Matching and `None`

To match `None`, use:

```python
case None:
```

This is a literal singleton pattern.

Do not use:

```python
case x:
```

and expect it to compare with an outer `x`.

Singleton patterns for `None`, `True`, and `False` are common and clear.

## 37.41 Pattern Matching and Security

Pattern matching may execute user code.

Potential execution points include:

```text
equality comparison
attribute access
descriptor access
mapping methods
sequence methods
guard expressions
```

For trusted in-memory objects, this is normal.

For untrusted objects with hostile methods, pattern matching should be treated like ordinary Python execution, not as a safe declarative query.

## 37.42 Inspecting Pattern Matching

Use `dis` to inspect match bytecode.

```python
import dis

def f(value):
    match value:
        case [x, y]:
            return x + y
        case {"x": x}:
            return x
        case _:
            return 0

dis.dis(f)
```

Look for:

```text
subject handling
pattern-specific checks
unpack operations
mapping operations
jumps between cases
stores for captured names
guard evaluation
return paths
```

The exact bytecode changes across Python versions.

## 37.43 A Minimal Pattern Matcher

A tiny structural matcher for lists can show the idea.

```python
def match_pair(value):
    if isinstance(value, (list, tuple)) and len(value) == 2:
        x, y = value
        return True, {"x": x, "y": y}
    return False, {}
```

Use:

```python
ok, binds = match_pair([1, 2])
if ok:
    print(binds["x"] + binds["y"])
```

This mirrors one small part of:

```python
match value:
    case [x, y]:
        print(x + y)
```

CPython does this through compiled bytecode and runtime helpers rather than a dictionary of bindings.

## 37.44 Common Misunderstandings

| Misunderstanding | Correct model |
|---|---|
| `match` is only a switch statement | It performs structural matching and binding |
| `case x` compares to variable `x` | It captures the subject into `x` |
| `_` is a normal capture | `_` is a wildcard in patterns |
| The subject is evaluated for every case | It is evaluated once |
| Pattern matching is side-effect free | It can call equality, descriptors, guards, and attribute hooks |
| Failed matches are exceptions | Normal pattern failure falls through to the next case |
| Class patterns inspect fields directly | They use attribute access and `__match_args__` |
| Pattern matching is always faster than `if` | It still performs runtime checks |

## 37.45 Reading Strategy

Start with scalar cases:

```python
def f(x):
    match x:
        case 0:
            return "zero"
        case _:
            return "other"
```

Then add structure:

```python
def f(x):
    match x:
        case [a, b]:
            return a + b
        case {"name": name}:
            return name
```

Then add classes:

```python
class Point:
    __match_args__ = ("x", "y")

def f(p):
    match p:
        case Point(0, y):
            return y
        case Point(x, y):
            return x + y
```

For each version:

```python
import dis
dis.dis(f)
```

Track:

```text
where the subject is stored
where each case begins
which checks can fail normally
which operations can raise
where names are bound
where guards run
where fallback jumps go
```

## 37.46 Chapter Summary

Pattern matching is CPython’s structural conditional dispatch system. It evaluates a subject once, tries cases in order, checks patterns, binds names, evaluates guards, and executes the first matching body.

The core model is:

```text
evaluate subject once
    ↓
try case pattern
    ↓
if pattern fails: clean up and try next case
    ↓
if pattern succeeds: bind names
    ↓
if guard exists: evaluate guard
    ↓
if guard true or absent: execute body
   
