Python match-case (switch-case?)

As of Python 3.10 we have a Python feature known as the Match-Case Statement.

It was proposed on PEP 622 which was replaced by PEP 634 by the name of Structural Pattern Matching.

match-case looks similar to the switch-case statement in other languages, but it is quite a bit more powerful.

For starters, there is no break to break the sequence of comparisons, it will match only one case and that’s it.

If none matches, it will go to the next line of code.

Code Examples

Let’s see match-case in action.

Comparing with a if statement

As a first example, let’s see how it compares to a regular if statement.

Here we have a function that takes a phone country code and prints the corresponding country.

55 prints Brazil, 91 prints Japan, and anything else returns ‘Other Country’.

def country_phone_code(code):
    if code == 55:
        print('Brazil')
    elif code == 91:
        print('Japan')
    else:
        print('Other Country')

country_phone_code(91)
Japan

The same logic using match-case will be like this:

def country_phone_code(code):
    match code:
        case 55:
            print('Brazil')
        case 91:
            print('Japan')
        case _: 
            print('Other Country')

country_phone_code(1)
Other Country

Notice how the else is replaced by the wildcard _.

Matching Multiple Patterns in a Single case

This example shows how you can match more than one pattern in a single case.

The code will print 1 if the country is either ‘USA’ or ‘Canada’.

def country_phone_code(country):
    match country:
        case 'Brazil':
            print(55)
        case 'USA' | 'Canada':
            print(1)
        case 'Japan':
            print(91)
        case _:
            print('Other Country')

country_phone_code('Canada')
country_phone_code('USA')
1
1

Match a Tuple

You can match more complex data structures like tuples.

This one is interesting because you can make partial matches to check if you have 2 items in a tuple.

This is how flexible match-case is.

point = (5,2,3)

match point:
    case (0, 0):
        print("2D Origin")
    case (0, 0, 0):
        print("3D Origin")
    case (x,y):
        print(f'X = {x}, Y = {y}')
    case (x,y,z):
        print(f'X = {x}, Y = {y}, Z = {z}')
    case _:
        raise ValueError("Not a valid coordinate")
X = 5, Y = 2, Z = 3

Another good example of this this function where we pass a string with comma-separated values (CSV), split by , and then check if the split resulted in two items.

If it has only two items, it automatically assigns ‘bmw’ to a brand variable.

If it has three values, we simply let it pass.

Also note how the return statement is called right after the match-case ends.

def parse_csv(line_string):
    match line_string.split(','):
        case [name, color]:
            brand = 'bmw'
        case [brand, name, color]:
            pass
    return f'{brand} - {name} -{color}'

print(parse_csv('x10, blue'))
bmw - x10 - blue

Match a Dictionary

To match a dictionary we use a ‘key:value’ pattern for each case.

Here we check if the message is ‘success’ or ‘failure’ and print the corresponding message.

def check_message(message):
    match message:
        case {'success': message}:
            print(f'Success: {message}')
        case {'failure': message}:
            print(f'Something wrong: {message}')
        case _:
            print('Unknown')

message_success = {'success': 'OK!'}
message_failure = {'failure': 'ERROR!'}

check_message(message_success)
check_message(message_failure)
Success: OK!
Something wrong: ERROR!

Guard

There is also this extra feature called Guard which allows you to add an if clause to a pattern.

Changing the dictionary example from before, in the first case, the key has to be ‘success’ AND the message can’t be equals to None to have a match.

def check_message(message):
    match message:
        case {'success': message} if message is not None:
            print(f'Success: {message}')
        case {'failure': message}:
            print(f'Something wrong: {message}')
        case _:
            print('Unknown')

message_success = {'success': None}
check_message(message_success)
Unknown

I always recommend you to read the official docs, in this case PEP 636 is a good tutorial with other examples you can go through.

Watch on Youtube

You can also watch this content on Youtube: