Locked learning resources

Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Locked learning resources

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Understanding Pattern Matching Limitations

00:00 Pattern matching is powerful, but it’s not all powerful. Let’s look at some common difficulties you might have when applying pattern matching. Treating match as an equivalent to a C-style switch statement, writing patterns to match on set objects, and what to do when case clauses overlap.

00:17 Structural pattern matching differs significantly from the switch statement found in many C family languages like C++ Java or even JavaScript.

00:26 Using switch, case matches on values only, not patterns. There’s a default keyword used to define the default case, and there’s also something called fall-through behavior.

00:37 When a match is found, all subsequent case blocks will run until a break keyword is encountered.

00:44 Here’s a side-by-side comparison. Can you spot the differences? On the left-hand side, we have a log_event function in C. It takes an event as an argument and switches on that event.

00:54 The cases keyboard and mouse are constant values being matched against. Each case uses the keyword break as well to prevent fall through after finding a match, and the default condition is marked by the default keyword.

01:07 Then we have the log() function defined in Python with pattern matching. log() matches against the result of passing an event to json.loads(), returning a dictionary and the case clauses use mapping patterns to describe the structure of the dictionary with no need for break statements, ending in a wildcard pattern to handle the default case.

01:27 Another way pattern matching can be tricky is when applied to matching on Python sets. Set objects are unordered, so they can’t be matched by sequence pattern.

01:36 To match a set, you have pretty much two options. The first is to use a class pattern and combine it with a guard. This can be handy for partial matching of set contents.

01:46 The other would be to use a value pattern to compare based on equality. This is useful if you want to match sets by their exact contents.

01:56 Again, on the left we have a class pattern with a guard. def is_authorized_user(): match user_roles: case set(roles) if roles & {"admin", "staff"}: return True case _: return False. set(roles) in the first case clause is another way of binding a local variable with a class pattern and it works for most built-in Python classes.

02:22 Then the ampersand works as the set intersection operator. So if roles is a set and it shares any elements with the set of admin and staff, you return True.

02:33 All other cases return False. On the right, the value pattern technique class Roles: AUTHORIZED = {"admin", "staff"} def is_authorized user(): match user_role: case role in Roles.AUTHORIZED: return True case _: return False. The Roles class here provides a namespace for the AUTHORIZED set.

02:58 By matching by value, you’re now using equality to compare the set of user roles with the set of Roles.AUTHORIZED. Writing the case clause like this, the two sets must be an exact match.

03:11 Now what about handling overlapping patterns? When using pattern matching, you should consider whether the same subject may match to multiple different case clauses.

03:20 If so, notice if this leaves one or more clauses unreachable in some cases. Then, reorder your patterns in descending order of specificity.

03:29 Think about how you could use pattern matching to solve a classic programming interview question. FizzBuzz. FizzBuzz looks at the numbers from one to 100 and does something different based on the value of each number.

03:40 For numbers divisible by three, it prints Fizz for numbers divisible by five, it prints Buzz and for numbers divisible by 15, it prints FizzBuzz. On the left, for x in range(1, 101): match x: case _: if x % 3 == 0: print("Fizz"), case _: if x % 5 == 0: print("Buzz"), case _: if x % 15 == 0: print("FizzBuzz") case _: print(x).

04:11 You might not see it at first, but there is a problem with this code because anything divisible by 15 is also divisible by both three and five, the FizzBuzz case is unreachable and you probably also won’t be getting a job offer.

04:24 On the right, we have the solution. Place the most specific case clause first, FizzBuzz. Only if this case is not matched, will the broader case clauses, Fizz and Buzz be considered.

04:36 Now FizzBuzz will print as intended, and you’re moving on to salary negotiations.

04:41 Okay, with all of this knowledge in hand, you’re about ready to unleash your pattern matching skills on the world. All that we have left is the summary, a quick review of everything you’ve learned.

Become a Member to join the conversation.