I have a class Expr
that can contain an array of slugs, the first slug defines a type of operation, and in 1 case it can be followed by either 1 or 2 more slugs. Is there a way to use structural pattern matching in such a way that the last slug gets a default value when it's not given? Here are some close-ish attempts:
class Expr:
def __init__(self):
self.slugs = ["flows", "step1"]
e = Expr()
Solution 1:
This one works but requires me to add validation logic and duplicates the wildcard error logic, which I could otherwise fall back on:
match e:
case Expr(slugs=["flows", step, *output]):
if len(output) > 1:
raise Exception("Invalid expression")
output = output[0] if output else None
case _:
raise Exception("Invalid expression")
Solution 2:
This one doesn't work because one branch doesn't bind the output
(SyntaxError: alternative patterns bind different names):
match e:
case Expr(slugs=["flows", step]) | Expr(slugs=["flows", step, output]):
Solution 3:
This one would be my ideal (SyntaxError: invalid syntax):
match e:
case Expr(slugs=["flows", step, output = None]):
I know solution 1 sort of does the job and it's a nitpick, but is it possible to get to a solution where the default value of the output
variable can be bound within the case
statement?
One approach is to use a guard after your Expr
match statement. The guard can check if output
is empty, in which case an assignment expression simply sets output
to None
, or if the length of output
is less than 2
. If either of those conditions are True
, then control passes to the body of the first case
statement. If not, then your default case _
is entered and the exception is raised:
match e:
case Expr(slugs=["flows", step, *output]) if (output:=output or None) is None or len(output) < 2:
print(output)
case _:
raise Exception("Invalid expression")
Usage examples:
>>> class Expr:
... def __init__(self, slugs):
... self.slugs = slugs
...
>>> e = Expr(["flows", "step1", "step2"])
>>> match e:
... case Expr(slugs=["flows", step, *output]) if (output:=output or None) is None or len(output) < 2:
... print(output)
... case _:
... raise Exception("Invalid expression")
...
['step2']
>>> e = Expr(["flows", "step1"])
>>> match e:
... case Expr(slugs=["flows", step, *output]) if (output:=output or None) is None or len(output) < 2:
... print(output)
... case _:
... raise Exception("Invalid expression")
...
None
>>> e = Expr(["flows", "step1", "step2", "step3"])
>>> match e:
... case Expr(slugs=["flows", step, *output]) if (output:=output or None) is None or len(output) < 2:
... print(output)
... case _:
... raise Exception("Invalid expression")
...
Traceback (most recent call last):
File "<stdin>", line 5, in <module>
Exception: Invalid expression