Kodeclik Logo

Our Programs

Courses

Gifting

Learn More

Schedule

Kodeclik Blog

Python “switch” statement: the match-case

A switch statement is a language construct that gives a few different options and something different to be done for each option. In Python the switch statement is called a “match case”.

Here is a simple example of how it works:

pet = input("What pet do you want? ")

match pet:
    case "dog":
        print("Woof! You got a loyal friend.")
    case "cat":
        print("Meow! You got a furry companion.")
    case "fish":
        print("Blub blub! You got a swimming buddy.")
    case "bird":
        print("Tweet! You got a feathered friend.")
    case _:
        print("Sorry, we don't have that pet.")

This first example demonstrates a pet selection program where the user inputs their desired pet, and the match-case statement provides a tailored response for dogs, cats, fish, and birds, with a default message for any other input. This showcases how match-case can handle specific string inputs and provide unique outputs for each case.

More examples of match-case

We can use switch statements to setup a grading system:

grade = int(input("What's your score? "))

match grade:
    case 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100:
        print("A: Excellent!")
    case 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89:
        print("B: Good job!")
    case 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79:
        print("C: Not bad.")
    case 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69:
        print("D: You can do better.")
    case _:
        print("F: You need to study more.")

The above code illustrates a grading system that categorizes numerical scores into letter grades. It uses the match-case statement with multiple values per case to group score ranges, demonstrating how to handle numerical inputs and use the or (|) operator within cases.

You can distinguish between days of the week using a match statement:

day = input("Enter a day of the week: ").lower()

match day:
    case "monday" | "tuesday" | "wednesday" | "thursday" | "friday":
        print("It's a school day!")
    case "saturday" | "sunday":
        print("It's the weekend!")
    case _:
        print("That's not a day of the week.")

Here we check for days of the week, grouping weekdays and weekend days together in their respective cases. This shows how match-case can handle multiple conditions in a single case and convert input to lowercase for easier matching.

Finally, how about a calculator?

num1 = int(input("Enter first number: "))
num2 = int(input("Enter second number: "))
operation = input("Enter +, -, *, or /: ")

match operation:
    case "+":
        print(f"{num1} + {num2} = {num1 + num2}")
    case "-":
        print(f"{num1} - {num2} = {num1 - num2}")
    case "*":
        print(f"{num1} * {num2} = {num1 * num2}")
    case "/":
        print(f"{num1} / {num2} = {num1 / num2}")
    case _:
        print("I don't know that operation.")

In this example, we create a simple calculator that performs basic arithmetic operations based on user input. This program demonstrates how match-case can be used with both numerical and string inputs to execute different calculations

Finally, here is a greeter in Python:

def greet(language):
    match language:
        case "English":
            return "Hello!"
        case "Spanish":
            return "Hola!"
        case "French":
            return "Bonjour!"
        case "German":
            return "Guten Tag!"
        case _:
            return "I don't know that language."

If we run it like:

print(greet("Spanish"))  

we will get:

Hola!

All the above examples show how the match-case statement can handle different types of inputs and provide different responses based on the input. It's a neat way to organize your code when you have multiple possible outcomes based on a single value.

Python switch statement: match-case

Match-case with conditions

The elements in each case don’t have to be exact values or just multiple values strung together by an OR condition. They can be more complex constraints like so:

def grade_feedback(score):
    match score:
        case x if x >= 90:
            return "Excellent!"
        case x if x >= 80:
            return "Good job!"
        case x if x >= 70:
            return "Not bad."
        case x if x >= 60:
            return "You passed."
        case _:
            return "You need to study more."

As a second example, we can do a match-case with tuple patterns:

def analyze_point(point):
    match point:
        case (0, 0):
            return "Origin"
        case (0, y):
            return f"Y-axis at y={y}"
        case (x, 0):
            return f"X-axis at x={x}"
        case (x, y) if x == y:
            return f"On the line y=x at ({x}, {y})"
        case (x, y):
            return f"Point at ({x}, {y})"

The analyze_point function takes a single argument point, which is expected to be a tuple representing coordinates in a 2D plane (x, y). The function then uses a match-case statement to categorize the point based on its coordinates. Here's what each case does:

case (0, 0): This checks if the point is at the origin (0, 0). If so, it returns "Origin".

case (0, y): This matches any point on the Y-axis, where x is 0 and y can be any value. It returns a string indicating it's on the Y-axis and specifies the y-coordinate.

case (x, 0): This matches any point on the X-axis, where y is 0 and x can be any value. It returns a string indicating it's on the X-axis and specifies the x-coordinate.

case (x, y) if x == y: This checks if the x and y coordinates are equal, which means the point lies on the line y=x. It returns a string indicating this and specifies the coordinates.

case (x, y): This is the default case that matches any other point. It simply returns the coordinates of the point.

The function uses pattern matching to destructure the input tuple and bind its values to variables (x and y) in each case. This allows for easy access to the coordinates within each case block.

Here are some example outputs:

print(analyze_point((0, 0)))    # Output: Origin
print(analyze_point((0, 5)))    # Output: Y-axis at y=5
print(analyze_point((3, 0)))    # Output: X-axis at x=3
print(analyze_point((4, 4)))    # Output: On the line y=x at (4, 4)
print(analyze_point((2, 3)))    # Output: Point at (2, 3)

Key differences between the match-case statement and if-elif-else in Python

You might ask - I can do this using a cascaded set of if-elif-else statements. What is the big deal? For instance the first example above could have been re-written as:

pet = input("What pet do you want? ")

if pet == "dog":
    print("Woof! You got a loyal friend.")
elif pet == "cat":
    print("Meow! You got a furry companion.")
elif pet == "fish":
    print("Blub blub! You got a swimming buddy.")
elif pet == "bird":
    print("Tweet! You got a feathered friend.")
else:
    print("Sorry, we don't have that pet.")

This if-elif-else structure accomplishes the same task as the match-case statement. It checks the value of pet against each condition sequentially. The first condition that evaluates to True will have its corresponding code block executed. If none of the specific conditions are met, the else block (equivalent to the case _ in the match-case version) is executed.

The main differences are:

1. Syntax: The if-elif-else structure uses more lines and is slightly more verbose.

2. Readability: For simple cases like this, both versions are quite readable. However, for more complex patterns, the match-case syntax can sometimes be clearer.

3. Functionality: In this simple example, both versions function identically. However, match-case has some advanced pattern matching capabilities that can be more cumbersome to replicate with if-elif-else statements.

The match-case statement introduced in Python 3+ thus offers several key advantages over traditional if-elif-else chains:

1. Pattern matching capabilities: Match-case allows for more complex pattern matching beyond simple equality comparisons. It can match against data structures, unpack values, and use wildcard patterns.

2. Improved readability: For multiple conditions, match-case tends to be more readable and concise compared to long if-elif-else chains.

3. Efficiency: Match-case can be more efficient, especially with complex matching patterns, as it doesn't need to check all possible values sequentially.

4. Exhaustiveness checking: The compiler can check if all possible cases are covered, helping prevent errors from unhandled cases.

5. Structural decomposition: Match-case excels at breaking down complex data structures and extracting relevant information.

6. Support for OR patterns: Multiple patterns can be combined in a single case using the | operator.

7. Guard clauses: Additional conditions can be added to case statements using "if" guards.

8. Maintainability: The clear structure of match-case can make code easier to maintain and modify.

However, it's worth noting that if-elif-else chains are still useful for simpler conditional logic and remain more familiar to many Python developers. The choice between match-case and if-elif-else often depends on the complexity of the conditions being evaluated and the structure of the data being matched against.

Can match-case statements be nested within each other?

Yes, match-case statements in Python can be nested within each other. This allows for more complex pattern matching and handling of hierarchical data structures. Below is an example of how nested match-case statements work:

def process_data(data):
    match data:
        case {"type": "person", "details": details}:
            match details:
                case {"age": age, "name": name} if age >= 18:
                    print(f"{name} is an adult")
                case {"age": age, "name": name}:
                    print(f"{name} is a minor")
        case {"type": "animal", "species": species}:
            print(f"This is an animal of species {species}")
        case _:
            print("Unknown data type")

In this example, the outer match-case statement checks the "type" of the data. For the "person" type, there's a nested match-case statement that further examines the "details". The nested match-case handles different cases based on the person's age.

Here are some examples of this function in action:

# Example usage
process_data({"type": "person", "details": {"age": 25, "name": "Alice"}})
process_data({"type": "person", "details": {"age": 15, "name": "Bob"}})
process_data({"type": "animal", "species": "dog"})
process_data({"type": "plant"})

The output will be:

Alice is an adult
Bob is a minor
This is an animal of species dog
Unknown data type

This example demonstrates how nested match-case statements can handle complex, hierarchical data structures effectively. In particular, nested match statements work well with dictionaries, allowing you to perform pattern matching on nested structures.

Note that Python's match-case statement was introduced only in Version 3.10, so if you use an older version, the above codes will not work. You will need to upgrade your Python version.

If you like learning about Python’s match-case, learn about other control structures in Python and how to do exception handling in Python!

Want to learn Python with us? Sign up for 1:1 or small group classes.

Kodeclik sidebar newsletter

Join our mailing list

Subscribe to get updates about our classes, camps, coupons, and more.

About

Kodeclik is an online coding academy for kids and teens to learn real world programming. Kids are introduced to coding in a fun and exciting way and are challeged to higher levels with engaging, high quality content.

Copyright @ Kodeclik 2024. All rights reserved.