Skip to content
aviral gupta

// B2.4 · ~30 min · Beginner

Pattern matching with match

After this lesson you can choose between cases with match, take a list apart with patterns that capture its items, and add conditions with guards.

Lesson 4 of 5 in B2 Control flow

You will be able to

  • Match a value against literals, alternatives joined with | and the _ wildcard
  • Take a list apart with sequence patterns and capture names, including *rest
  • Add guards with if, and match dictionaries and types with mapping and class patterns
  1. Warm-up · Activity 1 of 7

    Warm-up from B2.3: what does this print?

    for n in [1, 3, 5]:
        if n % 2 == 0:
            print("even:", n)
            break
    else:
        print("no even number")
  2. Predict · Activity 2 of 7

    Predict before you read on: what does this print?

    status = 418
    
    match status:
        case 200:
            print("OK")
        case 404:
            print("Not found")
        case _:
            print("Other")
  3. Practice · Activity 3 of 7

    Fill in the symbol that lets one case match "sat" or "sun".

    day = "sun"
    
    match day:
        case "sat" ____ "sun":
            print("weekend")
        case _:
            print("weekday")
    case "sat" "sun":
  4. Practice · Activity 4 of 7

    split() turns the text into a list of words. What does this print?

    command = "go north".split()
    
    match command:
        case ["quit"]:
            print("bye")
        case ["go", direction]:
            print("going", direction)
        case _:
            print("unknown")
  5. Practice · Activity 5 of 7

    Match each pattern to what it matches.

  6. Brain teaser · Activity 6 of 7

    Brain teaser. QUIT is meant to be a constant. What does this print?

    QUIT = "q"
    key = "x"
    
    match key:
        case QUIT:
            print("quitting", QUIT)
  7. Apply · Activity 7 of 7

    Mini-task. Write a tiny calculator: read one line with input(), split it, and match the words. add 2 3 prints 5, neg 4 prints -4, quit prints bye, and anything else prints unknown command. Convert the captured words with int().

    Check your work against this list

Build it yourself

Read the worked example, then write the exercises. Your code runs in your browser or on your computer and is never uploaded.

Worked example

Commands for a text game

A text adventure reads commands such as go north or take lamp key. The program splits each command into words and matches the list: exact commands, a guard that allows only four directions, *things to take any number of items, | for two spellings, and a wildcard for everything else. Add your own commands to the list and run it again.

main.py

# A few commands a player might type.
commands = ["look", "go north", "go up", "take lamp key", "i", "", "dance now"]
inventory = []

for line in commands:
    match line.split():
        case ["look"]:
            print("You are in a dark hall.")
        case ["go", direction] if direction in ["north", "south", "east", "west"]:
            print("You walk", direction)
        case ["go", other]:
            print("You cannot go", other)
        case ["take", *things]:
            for thing in things:
                inventory.append(thing)
            print("Taken:", things)
        case ["inventory" | "i"]:
            print("You carry:", inventory)
        case []:
            print("Say something.")
        case [verb, *_]:
            print("I do not know how to", verb)

Run it with

python main.py

Output

You are in a dark hall.
You walk north
You cannot go up
Taken: ['lamp', 'key']
You carry: ['lamp', 'key']
Say something.
I do not know how to dance
  • go up fails the guard of the first go case, so match tries the next case, ["go", other].
  • *things collects every word after take, here two, into a list.
  • "".split() is the empty list, which case [] matches.
  • case [verb, *_] catches every other non-empty command and keeps only the first word.
Change it and run it

Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.

The first run downloads Python for your browser (up to 6.5 MB) and keeps it cached. Your code stays on your device.

Exercises

Exercise 1 of 2

HTTP status text

The program reads an HTTP status code as a whole number. Use match to print OK for 200, Redirect for 301 or 302, Not found for 404, Server error for 500 and Unknown for anything else. Combine 301 and 302 in one case with |.

Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.

The first run downloads Python for your browser (up to 6.5 MB) and keeps it cached. Your code stays on your device.

Hints
  1. Hint 1

    match code: with one case per status, each followed by an indented print.

  2. Hint 2

    case 301 | 302: matches either code.

  3. Hint 3

    Finish with case _: print("Unknown") as the last case.

Show a solution

One way to solve it. Yours can look different and still pass the checks.

code = int(input())

match code:
    case 200:
        print("OK")
    case 301 | 302:
        print("Redirect")
    case 404:
        print("Not found")
    case 500:
        print("Server error")
    case _:
        print("Unknown")
Run it on your computer

Install Python 3.14 or newer. Save these files in one folder, open a terminal in that folder, and run the commands below.

main.py

code = int(input())

# Match code and print its text.
print("Unknown")

test_main.py

from learnrun import run_main


def status(code):
    return run_main(f"{code}\n").strip()


def test_ok_and_not_found():
    """200 is OK and 404 is Not found"""
    got = status(200), status(404)
    assert got == ("OK", "Not found"), f"for 200 and 404 the program printed {got!r}"


def test_redirects():
    """301 and 302 are both Redirect"""
    got = status(301), status(302)
    assert got == ("Redirect", "Redirect"), f"for 301 and 302 the program printed {got!r}"


def test_server_error():
    """500 is Server error"""
    got = status(500)
    assert got == "Server error", f"for 500 the program printed {got!r}, expected 'Server error'"


def test_unknown():
    """Any other code is Unknown"""
    got = status(418)
    assert got == "Unknown", f"for 418 the program printed {got!r}, expected 'Unknown'"

On macOS and Linux, type python3 wherever these commands say python, as in the first lesson.

Run the program:

python main.py

Run the checks (needs learnrun.py in the same folder):

python learnrun.py test
Download learnrun.py

Exercise 2 of 2

Area of a shape

The program reads a line such as square 5 or rect 3 4. Split it and match the words. Print the area of a square or a rectangle as a whole number. If a size is not above 0, print invalid, using a guard. For anything else print unknown shape.

Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.

The first run downloads Python for your browser (up to 6.5 MB) and keeps it cached. Your code stays on your device.

Hints
  1. Hint 1

    case ["square", side]: captures the size as a string; int(side) turns it into a number.

  2. Hint 2

    A guard goes after the pattern: case ["square", side] if int(side) > 0:.

  3. Hint 3

    After the guarded cases, case ["square", _] | ["rect", _, _]: catches the right shapes with bad sizes.

Show a solution

One way to solve it. Yours can look different and still pass the checks.

words = input().split()

match words:
    case ["square", side] if int(side) > 0:
        print(int(side) * int(side))
    case ["rect", width, height] if int(width) > 0 and int(height) > 0:
        print(int(width) * int(height))
    case ["square", _] | ["rect", _, _]:
        print("invalid")
    case _:
        print("unknown shape")
Run it on your computer

Install Python 3.14 or newer. Save these files in one folder, open a terminal in that folder, and run the commands below.

main.py

words = input().split()

# Match words: ["square", side] or ["rect", width, height].
print("unknown shape")

test_main.py

from learnrun import run_main


def area(line):
    return run_main(line + "\n").strip()


def test_square():
    """square 5 has area 25"""
    got = area("square 5")
    assert got == "25", f"for square 5 the program printed {got!r}, expected '25'"


def test_rect():
    """rect 3 4 has area 12"""
    got = area("rect 3 4")
    assert got == "12", f"for rect 3 4 the program printed {got!r}, expected '12'"


def test_invalid_sizes():
    """Sizes of 0 or less are invalid"""
    got = area("square 0"), area("rect 3 -1")
    assert got == ("invalid", "invalid"), f"for square 0 and rect 3 -1 the program printed {got!r}"


def test_unknown():
    """Other shapes and wrong word counts are unknown"""
    got = area("circle 2"), area("rect 3")
    assert got == ("unknown shape", "unknown shape"), f"for circle 2 and rect 3 the program printed {got!r}"

On macOS and Linux, type python3 wherever these commands say python, as in the first lesson.

Run the program:

python main.py

Run the checks (needs learnrun.py in the same folder):

python learnrun.py test
Download learnrun.py

Common mistakes

A bare name used as a constant

QUIT = "q"
key = "x"
match key:
    case QUIT:
        print("quitting")
    case _:
        print("other key")

What Python prints

SyntaxError: name capture 'QUIT' makes remaining patterns unreachable

Why, and the fix

A bare name in a case captures any value, so every case after it could never run, and Python refuses the file. Compare with the literal instead: case "q":. Named constants work only as dotted names, such as keys.QUIT, which you will meet with modules and classes.

or instead of |

day = "sat"
match day:
    case "sat" or "sun":
        print("weekend")

What Python prints

SyntaxError: invalid syntax

Why, and the fix

Patterns are not expressions, so or is not allowed in them. Alternatives are joined with a bar: case "sat" | "sun":.

The wildcard first

n = 1
match n:
    case _:
        print("anything")
    case 1:
        print("one")

What Python prints

SyntaxError: wildcard makes remaining patterns unreachable

Why, and the fix

case _: matches everything, and match stops at the first case that fits, so no case below it could ever run. Put the specific cases first and the wildcard last, as you would put else at the end of an if chain.

Python in the browser: Pyodide 314.0.7, MPL-2.0. Licence and source

Exit ticket

5 questions, no hints. Score 80% or more to complete the lesson.

Finish every activity above to unlock the exit ticket.

Report a problem

Spotted something wrong or unclear? Say what, and it will be checked and fixed.

#

At least 20 characters.

Only if you want a reply.

Key ideas

match tries the cases from the top

match value: compares the value with each case pattern in turn, and runs only the first case that matches, like an if and elif chain. A literal such as case 404: or case "quit": matches an equal value. case 401 | 403: matches either one. case _: is the wildcard: it matches anything, so it goes last and works like else. Without it, a value that matches no case runs nothing, and no error is raised. Python refuses a case _: without a guard that is not the last one.

Sequence patterns and capture names

A pattern can look like a list: case ["go", direction]: matches a list of exactly two items whose first item is "go", and binds the second to the name direction. A bare name is a capture pattern: it matches anything and assigns it, so case QUIT: does not compare with a variable called QUIT. case [first, *rest]: matches a list of at least one item; rest gets the others as a list. Strings are not matched as sequences, so text.split() turns a line into a list of words first.

Guards, dicts and types

A guard adds a condition: case [x, y] if x == y: matches only when the pattern fits and the condition is true; otherwise match tries the next case. A mapping pattern matches a dictionary, a type a later module covers: case {"type": "click", "x": x}: needs those keys and ignores any others. A class pattern checks the type: case int(): matches any integer, True and False included, and case str(): any string. They also take arguments, such as Point(x=0), once you write classes.

Sources

Last reviewed September 29, 2026