patma icon indicating copy to clipboard operation
patma copied to clipboard

Allow missing __match_args__ to accept a single positional arg

Open brandtbucher opened this issue 4 years ago • 5 comments

It is useful to be able to match against both the type and the value of a target. Currently, the only way to do this is to manually assign self to some attribute on the returned proxy, or use a guard.

How about this: if __match_args__ is None or is missing from the proxy (as it is from object, by default), we allow a single positional argument to ~test for equality~ continue matching against the proxy itself. As a result, all of these examples will just work by default:

from numbers import Real

specials = {"spam", "eggs", "cheese"}

match x:
    case bool(True):  # Doesn't match 1 or 1.0.
        ...
    case Real(42):
        ...
    case set(.specials):  # Doesn't match frozensets.
        ...

Currently, they must be spelled as:

match x:
    case bool(real=1):
        ...
    case Real() if x == 42:
        ...
    case set() if x == specials:
        ...

If a proxy wants to disable this behavior, it should just assign __match_args__ = [].

brandtbucher avatar Jun 04 '20 15:06 brandtbucher

This looks very reasonable to me. I particularly like that this makes all these special cases with built-in objects and types just work. +1 from me.

Tobias-Kohn avatar Jun 04 '20 18:06 Tobias-Kohn

Yeah, I like this (in fact this is what I have often assumed would work). While it seems redundant to be able to write

match x:
  case int(i): ...

it's far from redundant as a subpattern:

match p:
  case Point(int(x), int(y)): # A point of two integers
    ...

gvanrossum avatar Jun 05 '20 04:06 gvanrossum

I just realized that this makes patterns like tuple([1, 2, 3]) work naturally too.

brandtbucher avatar Jun 05 '20 14:06 brandtbucher

I had hoped you had already implemented this, but it doesn't seem so:

>>> match "abc":
...   case str(x): print(x)
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: too many positional matches in pattern

Also:

I just realized that this makes patterns like tuple([1, 2, 3]) work naturally too.

And this is actually an argument for allowing (...) for sequence patterns, since then we could write it as the much more satisfying tuple((1, 2, 3)).

gvanrossum avatar Jun 09 '20 00:06 gvanrossum

This is implemented now. I've only had time to test some simple cases so far, so let me know if you notice any issues!

brandtbucher avatar Jun 09 '20 17:06 brandtbucher