After I retired, structural pattern matching was the feature that encouraged me to upgrade to 3.10. But once I started to play with it, I was disappointed. Why could I not have ‘a * math.sin(b)’ in a case statement? Why could I only have one sub-sequence, and not match [3, 4] from [1, 2, 3, 4, 5, 6, …]? As time has passed and I have continued to us it, I’ve been impressed.
There are probably many enhancements to structural pattern matching that could be made in the future and I would like to propose that one of them allows programmers to explicitly control the pattern matching, i.e. the case statement can call a user defined function/class passing the value of the variable to be matched and a string or ast tree describing the pattern. The code below shows what this could look like and it has been tested using a simple preprocessor.
#!python3.10
import pattern
ass = [1, 2, 3, 4, 5, 6, 7, 8 , 9, 'a', 'b', 'c', 'd']
for var in [ass, 5, 2, 'axxd', 'ab']:
print(F'\nTesting {var}')
# Note that the following code causes fatal syntax errors during compilation
match var with pattern.sequence: # (a), refers to the notes below
case [~2 as x, *y, ~5 as z]: # uses pattern.sequence
print(F'Interior', {x}, {y}, {z})
case 5 >= Y > 2 with pattern.logic as Y : # (b)
print(F"pattern {Y}")
case 5 with pattern.value as FRED: #
print(F"pattern.value with {FRED}")
case 'ab' with pattern.Null as AB: # (c)
print(F'match {AB}')
case r'a..d' with pattern.RegExp as REG: # (d)
print(F'match {REG}')
case _:
print("No match")
- The match statement is optionally enhanced, with specifying the name of the pattern matching code. This would be used for every case statement unless overridden.
- The case statement is optionally enhanced, with specifying an overriding pattern matcher and as naming the variable to bind.
- If no match or an internal error occurs the match function returns None, anything else signifies a match.
So currently
case [~2 as x, *y, ~5 as z]:
becomes
case dnx0 if pattern.sequence(dnx0, "~2 >> x, *y, ~5 >> z”) is not None:
I’ve implemented pattern matchers for
a) enhanced sequent unpacking for finite sequences, (~3 means return the value of list.index(3)) and sets a placeholder. as renamed to >> so the pattern is a legal ast tree,
b) matching logic expressions,
c) matching against a general expression, number or string, revert to builtin.
d) matching against regular expressions.
This is just syntactic sugar like pattern matching, but I think it looks better than lots of guards or if/else chains.