Skip to content

Instantly share code, notes, and snippets.

@jsbueno
Last active June 28, 2022 01:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jsbueno/c1f646554a144079c961159115aaaffe to your computer and use it in GitHub Desktop.
Save jsbueno/c1f646554a144079c961159115aaaffe to your computer and use it in GitHub Desktop.
Python match/case internals "hacky" class which allows one to match ranges without needing any expression guards
class Comparator:
def __init__(self, value, stage):
self.value = value
self.stage = stage
def __eq__(self, other):
return self.value >= other if self.stage == "start" else self.value < other
class Interval:
__match_args__ = ("start", "stop")
def __init__(self, value):
self.value = value
@property
def start(self):
return Comparator(self.value, "start")
@property
def stop(self):
return Comparator(self.value, "stop")
def __repr__(self):
return f"Wrapped value for range matching: {self.value}"
def m(n):
match Interval(n):
case Interval(0, 2):
print("first")
case Interval(2, 5):
print("second")
case Interval():
print("any")
case _:
print("not found")
@jsbueno
Copy link
Author

jsbueno commented Jun 28, 2022

The difficulty about matching ranges is that in a match/case statement, the literal values that would specify any range in a line like case Interval(0, 2): are never forwarded to the interval class: rather, they are kept in the code object where the match/case body is run. However, the __match_args__ mechanism allows that the values that are tested for equality with` those limits to be fetched from the Interval instance that is being compared.

So, the drawback is that the value to be range-checked have itself to be wrapped in an "Interval" class. Other than that, the ~20LoC above are enough to make everything work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment