Python 3.10: match-case syntax for catching exceptions

I am playing with this new match-case syntax in Python 3.10 and I had a thought whether one would be able to catch exceptions with it. Is it possible?

Let’s take a look!

>>> def say(something):
...     match something:
...         case "hello":
...             print("Hello to you!")
...         case TypeError:
...             print("Uhm, what was that you said?!")
...
>>> say(123)
Uhm, what was that you said?!
>>> say("hello")
Hello to you!

As you can see, you definitely can! Isn’t Python just amazing? Of course your answer is a resounding yes. :slight_smile:

2 Likes

ValueError is a non-dotted variable, so it tries to assign to it, and the assignment succeeds. Almost certainly not what is intended.

This is a misunderstanding of what’s going on here. Try adding a case something_else: after the case TypeError, which will tell you SyntaxError: name capture 'TypeError' makes remaining patterns unreachable: the case TypeError is not catching a TypeError, it is assigning something to the name TypeError.

4 Likes

I didn’t realize this. I thought I was catching a TypeError. Thanks for the clarification.

So the match-case syntax can’t catch an exception at all? If that’s true, then I guess I’ll have to go back to the good ol’ try-except.

@BowlOfRed, what do you mean by a non-dotted variable? Never heard of this term. What does it mean?

The new match/case feature is meant as a cleaner alternative to
lengthy if/elif/else and similar conditional chains. There doesn’t
seem to be any way to reimplement try/except clauses with it, but
those already work somewhat similarly to match/case anyway so I’m
not sure why you’d want to?

  1. match x won’t catch exceptions raised in x.
  2. To test that x is an instance of TypeError you have to use case TypeError() (note the parentheses).
  3. A name without a dot is interpreted as the assignment target. Case in point: case str: ... will assign x to str, but case builtins.str: ... will perform the equivalent of issubclass(x, str).
2 Likes

Wow, this is very informative for me, thank you very very much! I really appreciate this.

I’m mastering this new match-case syntax and you guys are very supportive here. I am going to use the match-case syntax throught my whole codebase wherever it’s feasible.

May I ask about the as pattern? Where is it syntactically correct to be used: in match and also in case, or just in one of them?

Ha, turns out that in match you can utilize the almighty walrus operator. That’s kinda cool. In case, you can use the as pattern. I always learn something new and it always amazes me.

Have you read the docs and the tutorial?

https://docs.python.org/release/3.10.0/reference/compound_stmts.html#the-match-statement

Tutorial: PEP 636 -- Structural Pattern Matching: Tutorial | Python.org

I don’t see anything to suggest that you can use as with either match
or case, nor do I understand why you would want to. What purpose do you
think as could be used in a match statement?

From the tutorial link:

match command.split():
    case ["go", ("north" | "south" | "east" | "west") as direction]:
        current_room = current_room.neighbor(direction)

The as-pattern matches whatever pattern is on its left-hand side, but also binds the value to a name.

1 Like

As @BowlOfRed explained in the example code above, there might be some as pattern use cases that are actually a clean way to implement an algorithm.

In the example, you don’t know which value (either “north”, “south”, “east”, or “west”) the user is going to input, so you bind all of the OR’ed values to a variable (in the example it is direction) and then the value that the direction variable is referencing is processed (whatever the value might happen to be, depends on the user input). A cool trick actually.

I’ve got a new question regarding this new match-case syntax.

How on Earth can I have a syntactically correct case statement that checks for whether the value of the subject is less than 0?

def is_less_than_zero(number):
    match number:
        case number < 0:  # The issue I'm having is here, I can't figure out what is the correct syntax
            print("Yes, this number is less than zero.")
        case _:
            print("No, this number is not less than zero.")

You can use guards as explained in PEP 636: Adding conditions to patterns.

1 Like

Aha! I was going to ask you where the “as” pattern was documented, but I
just found it:

https://docs.python.org/release/3.10.0/reference/compound_stmts.html#grammar-token-python-grammar-as_pattern

Thanks BowlOfRed, I just learned something new.

I don’t have Python 3.10 installed yet, so I haven’t tried this to see
if it works, but I think you can do either:

match some_expression:
    case number if number < 0:
        print("number is less than 0")
    case _:
        print("number is not less than 0")

or:

match some_expression:
    case number:
        if number < 0:
            print("number is less than 0")
        else:
            print("number is not less than 0")

but honestly, this does not look like a good match for the match
statement (pun intended!). Sometimes you should just use an if…else
statement.

1 Like

@steven.daprano, you are amazing! Thank you! The first (the top one) example works like a charm! Well, the second (the bottom one) example works as well, but the first one is much cleaner.

So, the solution to my problem is this:

def is_less_than_zero(random_number):
    match random_number:
        case random_number if random_number < 0:
            print("Yes, the number is less than zero.")
        case _:
            print("No, the number is not less than zero.")

I’m learning so much and I’m very grateful to all of you!

Thank you, @erlendaasland, for your hint. I’m kind of not too keen on the idea of having those if guards. I think they don’t help in readability.

The solution that @steven.daprano gave also adds an if statement to the code, but it’s visually more appealing to me if the if conditional is in the same line as the case expression.

I don’t understand your reply. The example I linked to has the guard on the same line as the case. It’s exactly the same as @steven.daprano suggested.

Ah, yes, my bad. I don’t know why I thought the if guard was not in the same line as the case expression. I probably read the second (the bottom one) example that @steven.daprano gave and after reading your comment and reading the tutorial I mixed things up. Sorry 'bout that.

1 Like