Search code examples
pythonstructural-pattern-matching

Why does Python's Structural Pattern Matching not support multiple assignment?


I was experimenting with Python Structural Pattern Matching and wanted to write a match statement capable of matching repeated occurrences in a sequence.

Suppose that I have the following list of tuples and was trying to match every pair in which the first element of the tuple is the same.

from itertools import combinations

objs = (('a', 'b'), ('c', 'd', 'e'), ('f',), ('a', 'g'), ('b', 'a'))
pairs = list(combinations(objs, 2))

The goal was my code to match the pair: (('a', 'b'), ('a', 'g')) as both tuples starts with 'a'.

My first attempt was:

from itertools import combinations

objs = (('a', 'b'), ('c', 'd', 'e'), ('f',), ('a', 'g'), ('b', 'a'))
pairs = list(combinations(objs, 2))

for pair in pairs:
  match pair:
    # This raises Syntax Error!
    case ((x, *y), (x, *z)): print('Found!')
    case _: pass

However this raises: SyntaxError: multiple assignments to name 'x' in pattern.

A possible work around I guess is to use guards in which one gives different names such as x1 and x2 and then matches only if x1 == x2, however this can quickly become quite messy if I want to enforce more than one equality. In my opinion using the same binding name is both elegant and practical with the obvious implication that the two should be the same.

And so I ask, is there any reason why Structural Pattern Matching enforces the variable names to be different? Is there a nicer way to accomplish this that I'm missing?


Solution

  • From PEP 635 – Structural Pattern Matching: Motivation and Rationale, section Capture Patterns:

    A name used for a capture pattern must not coincide with another capture pattern in the same pattern. This, again, is similar to parameters, which equally require each parameter name to be unique within the list of parameters. It differs, however, from iterable unpacking assignment, where the repeated use of a variable name as target is permissible (e.g., x, x = 1, 2). The rationale for not supporting (x, x) in patterns is its ambiguous reading: it could be seen as in iterable unpacking where only the second binding to x survives. But it could be equally seen as expressing a tuple with two equal elements (which comes with its own issues). Should the need arise, then it is still possible to introduce support for repeated use of names later on.