Match foo() as bar

I’ve been enjoying the match syntax, especially combined with typing support. I tend to find myself using the form:

import typing

def foo() -> typing.Literal['foo']:
    return 'foo'


if __name__ == '__main__':
    bar = foo()

    match bar:
        case 'foo':
            pass
        case _:
            raise typing.assert_never(bar)

Note that bar variable only exists to be used in the match block.

I propose a (hopefully) cleaner syntax:

match foo() as bar:
    case 'foo':
        pass
    case _:
        raise typing.assert_never(bar)

Thoughts?

You can already do this:

match foo():
    case 'foo':
        pass
    case _ as bar:
        typing.assert_never(bar)

(You shouldn’t do raise typing.assert_never(bar) FYI – the function raises an exception, it doesn’t return an exception :slight_smile: )

3 Likes

Thank you - this works perfectly.

1 Like

Another option, if you need to use the variable in multiple case blocks, is to use a walrus to assign the variable at the beginning of the match/case:

import typing

def foo() -> typing.Literal["foo"] | int: ...

match bar := foo():
    case 'foo':
        print("it's foo")
    case int():
        if bar > 99999:
            print("it's a big number")
        else:
            print("it's not such a big number")
    case _:
        typing.assert_never(bar)
2 Likes

Or just case bar:?

Indeed — I usually try to make the last match a wildcard match out of habit, and to be explicit that it’s meant to be exhaustive — but you’re quite right that, strictly speaking, a name-capture match is sufficient here

2 Likes