The biggest introduction of Python 3.10 was the Match-Case statement. This is the Python equivalent of the Java switch statement and is something that many programmers have been asking for a long time.
But now that this great command has been introduced, it is important to learn how to make the most out of it. Here is a quick guide on how the match-case statement works.
The Basics
First of all, let's see a basic example. Suppose we have a variable representing a color as a string. it can be "green"
, "red"
, "yellow"
, and "blue"
. In Python 3.9, you would have used an if statement with four branches.
Now, however, we can use a match statement. This will make your code easier to read and maintain. Here is the code to do it:
color = "yellow"
match color:
case "red":
print("The color is red")
case "yellow":
print("Wow, you picked yellow")
case "green":
print("We are using a green color")
case "blue":
print("Blue like the sea...")
First we define, after the match
keyword, the variable that we want to match. Then, each case starts with the case
keyword, followed by the pattern we want to check. The match-case statement will run only the code under the first case which was matched.
So, in this example, the match statement will print "Wow, you picked yellow"
. Now consider this other situation:
match color:
case "yellow":
print("Wow, you picked yellow")
case "blue":
print("Blue like the sea...")
case "yellow":
print("Yellow again!")
In this case, the second case that matches "yellow"
will never be executed, since the variable will enter the first case and then skip to the end of the statement (much like an if ... elif
case).
Combining Patterns
Now suppose we want to execute the same code for yellow
and purple
. It would be bad practice to write the same code twice, for two different cases.
Instead, we can use the |
operator to include multiple patterns in the same case:
match color:
case "yellow" | "purple":
print("Wow, you picked yellow or purple")
case "blue":
print("Blue like the sea...")
case "red":
print("Red here!")
Here the first case will be executed if the color is one of the two specified.
The catch-all case
Lastly, it may be that you want to have a case that will be always executed if the variable does not match any previous case. You can obtain this as follows:
color = "purple"
match color:
case "yellow":
print("Wow, you picked yellow")
case "blue":
print("Blue like the sea...")
case other_color:
print("You chose a different color:", other_color)
In the last case branch, other_color
is a variable that matches everything. So in this situation, since no other case matches our color, then other_color
will take the same value as color
and we will execute this code.
It's important to put this catch-all case as the last one: in fact, it will always match any input, and therefore the cases after it will never be executed.
Matching Over Lists
Now that we understand the basics, let's see a powerful feature of the Match statement: pattern matching over sequences.
The easiest thing we can do is to match specific elements:
my_list = [1, 2, 3]**match** my_list:
case [1, 2, 3]:
print("contains 1, 2, 3")
case [4, 5]:
print("Contains 4 and 5")
case _:
print("No match")
Here my_list
will execute the code in the first case, since the elements are the same. Note that we have also added a catch-all case at the end.
However, there is much more that we can do! First of all, we can match some elements to exact values, and leave others to variables:
my_list = [1, 2, 4]
match my_list:
case [1, 2]:
print("contains only 1 and 2")
case [1, 2, el]:
print("Last element is", el)
case _:
print("No match")
Look at the second case: this will be executed if the list contains three elements. The first two must be 1
and 2
, while the last one can be of any value. The variable el
will take the value of this last element, and we can use it inside the case as a normal variable.
In addition, we can split a list into the head (the first element) and the tail (a list containing all elements, except for the head):
match l:
case [head, *tail]:
print("First is", head)
print("Rest is", tail)
case []:
print("Empty")
This is particularly useful if we want to create a recursive function that does something on the head and then recurses on the rest of the list. For example:
def recursive_sum(my_list):
"""Calculate the sum of the elements with pattern matching"""
match my_list:
case []:
return 0
case [head, *tail]:
return head + recursive_sum(tail)
Here we calculate the sum of the list recursively: if a list is empty, the sum will be zero. Otherwise, the sum is the value of the head plus the recursive sum of the rest of the list.
Conditional Cases
Now let's see how we can “deactivate” some cases by using an if statement.
For example, suppose we have an integer n
, and we want to execute pattern matching. We have three cases: one if n
is zero, one if n<100
and the last one for all other cases. It is impractical to write 99 values for a single case, but luckily Python has the feature that we need: we can add if statements to a case.
Here is how we would create our Match:
num = 5
match num:
case 0:
print("It is zero")
case n if n<100:
print(n, "less than 100 but bigger than zero")
case _:
print("A really big number")
Without the if statement, the second case would be a catch-all case, so the third case would never be executed. By adding the if
, however, the second case is used only whenn<100
. Otherwise, the code will behave as if that case did not match.
Structural Pattern Matching
Lastly, we will see how we can use custom classes in the match statement.
Consider, for example, the class:
class ButtonClicked:
def __init__(self, mouse_button: str, x: int, y: int):
self.x = x
self.y = y
self.mouse_button = mouse_button
This class represents the click of the mouse on the screen. It stores the x and y coordinates, and a string that can be "left"
or "right”
, based on which button of the mouse was pressed.
Now we want to have two different cases, one for the left button and the other for the right one. This can be achieved as follows:
b = ButtonClicked("left", 3, 5)
match b:
case ButtonClicked(mouse_button="left"):
print("Left mouse clicked at", b.x, b.y)
case ButtonClicked(mouse_button="right"):
print("Right mouse clicked at", b.x, b.y)
In each case, we specify which value should be taken by the variable mouse_clicked
.
Conclusion
Thank you for reading this tutorial, I hope it was helpful!
If you want to learn more about the Match Case in Python, check out the following resources: