37

The new structural pattern matching feature in Python 3.10 is a very welcome feature. Is there a way to match inequalities using this statement? Prototype example:

match a:
    case < 42:
        print('Less')
    case == 42:
        print('The answer')
    case > 42:
        print('Greater')
gustafbstrom
  • 1,622
  • 4
  • 25
  • 44
  • 6
    Personally I would use a simple `if elif else` statement when matching (in)equalities and not _structural patterns_. – Krachtwerk Nov 07 '21 at 09:07

3 Answers3

49

You can use guards:

match a:
    case _ if a < 42:
        print('Less')
    case _ if a == 42:
        print('The answer')
    case _ if a > 42:
        print('Greater')

Another option, without guards, using pure pattern matching:

match [a < 42, a == 42]:
    case [True, False]:
        print('Less')
    case [_, True]:
        print('The answer')
    case [False, False]:
        print('Greater')
wjandrea
  • 28,235
  • 9
  • 60
  • 81
Ajax1234
  • 69,937
  • 8
  • 61
  • 102
  • 11
    In the first example I'd rather just use the old if/elif which is much easier to read IMO. – rotten Apr 08 '22 at 14:11
  • 1
    For the first `case` it seems that `case [True, _]:` also works and is consistent with the pattern in your second `case`. Or you could make the second one `case [False, True]:` if you wanted to make the consistency the other way. – Dennis Williamson Jul 11 '22 at 23:19
  • 2
    What's the point of the first one if it's basically just an if-elif with more steps? – wjandrea Feb 23 '23 at 16:22
  • @wjandrea match-case seems terribly designed :/ Should have allowed `match a: case < 42` – theonlygusti May 22 '23 at 19:22
  • 1
    @theonlygusti Well, TBF, this isn't what it's built for. It's very much *structural pattern matching*. Take a look at [this answer I wrote](/a/71151862/4518341) and how much cleaner match-case makes the parsing code. – wjandrea May 22 '23 at 20:21
4

In this example, it's simpler to use good ol' if-elif, even if it means repeating the variable name.

if a < 42:
    print('Less')
elif a == 42:
    print('The answer')
elif a > 42:
    print('Greater')

P.S. Using an enum and comparison function like in Thomas Sollie's answer is good for adding more structure to your program, but it seems like overkill for basic scripts and such.

Speaking of code style, avoid magic numbers: If all three 42's in your code represent the same thing, give it a name, for example:

the_answer = 42
if a < the_answer:
...
wjandrea
  • 28,235
  • 9
  • 60
  • 81
3

A match-case statement inherently is designed for matching equalities (hence the word "match"). In your prototype example you could achieve this by matching with an if clause (as proposed by other answers), however now you are in essence simply matching True and False, which seems redundant.

One way other languages solve this is via comparisons using Enums:

from enum import Enum


class Ordering(Enum):
    LESS = 1
    EQUAL = 2
    GREATER = 3


def compare(a, b):
    if a < b:
        return Ordering.LESS
    elif a == b:
        return Ordering.EQUAL
    elif a > b:
        return Ordering.GREATER


match compare(a, 42):
    case Ordering.LESS:
        print("Less")
    case Ordering.EQUAL:
        print("The answer")
    case Ordering.GREATER:
        print("Greater")
wjandrea
  • 28,235
  • 9
  • 60
  • 81
Thomas Sollie
  • 47
  • 1
  • 1
  • Off-topic, but that enum is incomplete for other numeric types. If the numbers could be floats, they could be NaN, which never compares less, equal, or greater, only not equal. And, hypothetically, you could have a third-party type that doesn't compare less, equal, greater, **or** not equal. So I might add a `NOT_ORDERABLE` member for that or have `compare()` throw a `TypeError`. – wjandrea May 22 '23 at 20:57
  • At that point I have a hard time justifying the use of a case statement when you can simply use the `if/elif`. It's half the lines and easier to read. – Marcel Wilson Aug 17 '23 at 15:00