On Thu, 16 Jul 2020 at 02:09, Guido van Rossum <[email protected]> wrote:
>
> On Wed, Jul 15, 2020 at 4:41 PM Oscar Benjamin <[email protected]>
> wrote:
>>
>> I've taken a look through PEP 622 and I've been thinking about how it
>> could be used with sympy.
>>
>> In principle case/match and destructuring should be useful for sympy
>> because sympy has a class Basic which defines a common structure for
>> ~1000 subclasses. There are a lot of places where it is necessary to
>> dispatch on the type of some object including in places that are
>> performance sensitive so those would seem like good candidates for
>> case/match. However the PEP doesn't quite seem as I hoped because it
>> only handles positional arguments indirectly and it does not seem to
>> directly handle types with variadic positional args.
>>
[snip]
>>
>> From a first glimpse of the proposal I thought I could do matches like this:
>>
>> match obj:
>> case Add(Mul(x, y), Mul(z, t)) if y == t:
>> case Add(*terms):
>> case Mul(coeff, *factors):
>> case And(Or(A, B), Or(C, D)) if B == D:
>> case Union(Interval(x1, y1), Interval(x2, y2)) if y1 == x2:
>> case Union(Interval(x, y), FiniteSet(*p)) | Union(FiniteSet(*p),
>> Interval(x, y)):
>> case Union(*sets):
>>
>> Knowing the sympy codebase each of those patterns would look quite
>> natural because they resemble the constructors for the corresponding
>> objects (as intended in the PEP). It seems instead that many of these
>> constructors would need to have args= so it becomes:
>>
>> match obj:
>> case Add(args=(Mul(args=(x, y)), Mul(args=(z, t)))) if y == t:
>> case Add(args=terms):
>> case Mul(args=(coeff, *factors)):
>> case And(args=(Or(args=(A, B)), Or(args=(C, D)))) if C == D:
>> case Union(args=(Interval(x1, y1), Interval(x2, y2))) if y1 == x2:
>> case Union(args=(Interval(x, y), FiniteSet(args=p))) |
>> Union(args=(FiniteSet(args=p), Interval(x, y))):
>> case Union(args=sets):
>>
>> Each of these looks less natural as they don't match the constructors
>> and the syntax gets messier with nesting.
>
>
> That's a really interesting new use case you're bringing up.
>
> You may have noticed that between v1 and v2 of the PEP we withdrew the
> `__match__` protocol; we've been brainstorming about different forms a future
> `__match__` protocol could take, once we have more practical experience. One
> possible variant we've been looking at would be something that would *only*
> be used for positional arguments -- `__match__` would just return a tuple of
> values extracted from the object that can then be matched by the
> interpreter's match machinery. Your use case could then (almost, see below)
> be handled by having `__match__` just return `self.args`.
That would work but something else just occurred to me which is that
as I understand it the intention of __match_args__ is that it is
supposed to correspond to the parameter list for __init__/__new__ like
class Thing2:
__match_args__ = ('first', 'second')
def __init__(self, first, second):
self.first = first
self.second = second
That is deliberate so that matching can have a similar logic to the
way that arguments are handled when calling __init__:
match obj:
case Thing2(1, 2):
case Thing2(1, second=2):
case Thing2(first=1, second=2):
...
Maybe __match_args__ could have a way to specify the variadic part of
a parameter list as well:
class ThingN:
__match_args__ = ('first', 'second', '*rest')
def __init__(self, first, second, *rest):
self.first = first
self.second = second
self.rest = rest
Then you can match with
match obj:
case ThingN(1, 2):
case ThingN(1, 2, 3):
case ThingN(first, second, *rest):
case ThingN(first, *second_and_rest):
case ThingN(*allargs):
...
The normal restrictions for combinations of keyword and positional
arguments could apply to the patterns as if __match_args__ was the
parameter list for a function.
Perhaps the * in '*rest' isn't as clear between quotes and some more
noticeable syntax could be used like
__match_args__ = ('first', 'second', ('rest',))
--
Oscar
_______________________________________________
Python-Dev mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at
https://mail.python.org/archives/list/[email protected]/message/SMN5GZHGURK2AQKTBES5Z6XLWPDUBNB6/
Code of Conduct: http://python.org/psf/codeofconduct/