Coming soon - Get a detailed view of why an account is flagged as spam!
view details
36
"Guarded" Match/Case statements
Post Body

I was doing some research into match/case statements trying to figure out how to compare the match value to a variable as opposed to a static entry and found a seeming lack of information on the topic. I was about to post here for help but ended up finding some info that helped me, so I figured I'd post here so that it might help others and that people can discuss it if they found it helpful.

If you've seen switch/case statements in other languages or started looking at the relatively new match/case in Python you are probably familiar with something like this:

BASIC MATCH/CASE

x = 1

match x:
    case 1:
        print("Number 1")
    case 2:
        print("Number 2")
    case str():
        print("It's a string")
    case {"key": "value"}:
        print("Dictionary with Keys and Values")
    case _:
        print("Didn't match anything")

We start matching against the variable X, testing each case from top to bottom. If it's the integer numbers 1 or 2, we print our "Number 1/2". Next we check to see if x is a string by seeing if it matches the built-in string class, then check to see if it a dictionary with a key called "key" and a corresponding value called "value". Finally if we missed everything above, we catch everything else with "_".

You may also know about being able to extract data from your matching variable into independent variables for use.

MATCH/CASE WITH ASSIGNMENTS

x = {"type": "order", "id": 24}

match x:
    case {"type": "order", "id": idnumber}:
        print(f"Order found with id number: #{idnumber}")

For instance, here we check to see if x is a dictionary with a key called "type" with the value set to "order". If so, we match, and we extract the value under the key "id" and store it in a variable called "idnumber". This is used in the fstring print statement, and of course we could use this in more complicated logic. Note that the value of "id" can be anything, but it MUST be present. If "id" is absent, we won't match this case at all.

My issue was, what if I want to match something in the dictionary against a variable, instead of assinging it to a variable. For instance, what if we have an order date and we want to reference it against today's date, which is calculated dynamically.

It turns out you can use an "if" statement along with the case statement, all on the same line. This makes it look a little cleaner than having your if statement nested inside the case statement, and you don't have an extra indent for your block of code.

GUARDED MATCH/CASE WITH ASSIGNMENTS

x = {"type": "order", "id": 24, "date": 123456}
todays_date = 123458

match x:
    case {"type": "order", "id": idnumber, "date": orderdate} if orderdate >= todays_date-30:
        print(f"Order found with id number: #{idnumber} and date {orderdate}")
    case {"type": "order", "id": idnumber, "date": orderdate} if orderdate < todays_date-30:
        print(f"Aging order found with id number: #{idnumber} and date {orderdate}")
    case _:
        print("Order not found")

Here we are checking to make sure that we have a dictionary with "type' set to "order", some "id" which we extract to the variable idnumber, and some "date" which we extract to orderdate. We then do a check to make sure that the order date is greater or equal to today's date minus 30. If so we print that data out. If the order is older, we match the second case. If we don't match either, we catch it with the default.

DEFAULT GUARDED MATCH/CASE

x = 5
y = 6
z = 5

match x:
    case _ if x == y:
        print("x equals y")
    case _ if x == z:
        print("x equals z")

We can even do something like this to entirely drive the case off an if statement. Of course we may want to debate if we should do this vs simply just using an if instead of a match/case; for something this simplistic a regular if conditional would probably be better but this demonstrates an ability that might be useful in another program.

And just as a final bonus, don't forget can even do complex matches looking inside classes with something like:

UNREASONABLE BUT FUNCTIONAL MATCH/CASE WITH CLASSES AND LAMBDAS BECAUSE WE CAN

class class1:
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c

l = [1, 2]
c1 = class1(1, 2, 3)

match c1:
    #The first equal sign here is actually an equality not an assignment!
    case class1(a=1, b=x, c=y) if x == next(filter((lambda q: q % 2 == 0), l)):
        print(f"Matched Class1 with values {x} {y}")

Don't ever actually do this, it's clearly Rube Goldberg code, and everyone will hate you if you do it. But it's mostly just here to prove that you can incorporate all sorts of crazy elements if you end up needing any... just think about if you should before you do.

Author
Account Strength
100%
Account Age
8 years
Verified Email
Yes
Verified Flair
No
Total Karma
144,117
Link Karma
8,472
Comment Karma
134,250
Profile updated: 1 month ago
Posts updated: 11 months ago

Subreddit

Post Details

We try to extract some basic information from the post title. This is not always successful or accurate, please use your best judgement and compare these values to the post title and body for confirmation.
Posted
2 years ago