Why do Python's match statements not raise an Exception when no pattern matches?

176 Views Asked by At

PEP 634 and PEP 635 introduce structural pattern matching. But no rationale is given why nothing happens, if none of the patterns matches:

var = 3
match var:
    case 1:
        pass
    case 2:
        pass

print("End is reached without Exception.")

From Erlang i am used to this raising an Exception. In Rust, this would not compile. In Python you always have to add an irrefutable pattern:

    case _:
        raise Exception("…")

Why is that?

2

There are 2 best solutions below

2
On

The Python match statement evaluates the value after the match keyword and checks it against the pattern (the code next to case). If there’s a match, the statements inside the case block will be executed with the bound variables. If there’s no match, nothing happens and the next statement is executed. If there's no match at all and no irrefutable pattern, None is returned as can be seen in the example below:

def match_case(var=3):
    match var:
        case 1:
            return 1
        case 2:
            return 2

print(match_case())

So yes, nothing seems to happen but it actually returns None. It wouldn't raise an Exception because this is not considered an Exception by the interpreter.

Furthermore, it is not compulsory to add the wildcard pattern i.e. case _. According to PEP634

A pattern is considered irrefutable if we can prove from its syntax alone that it will always succeed. In particular, capture patterns and wildcard patterns are irrefutable.

This does not suggest that one must include the wildcard pattern, rather it says that the wildcard pattern never fails to succeed if included.

2
On

According to the Python docs, "You may want to print an error message saying that the command wasn’t recognized when all the patterns fail. You could use the feature we just learned and write case [*ignored_words] as your last pattern."

Therefore, something like this can work

var = 3
match var:
    case 1:
        pass
    case 2:
        pass
    ....

    case _:
       # throw your error here
       pass

In this case if no number matches, the exception will be raised in the case with the '_' wildcard.