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: