On Thu, 16 Jul 2020 at 02:09, Guido van Rossum <gu...@python.org> wrote: > > On Wed, Jul 15, 2020 at 4:41 PM Oscar Benjamin <oscar.j.benja...@gmail.com> > 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 -- python-dev@python.org To unsubscribe send an email to python-dev-le...@python.org https://mail.python.org/mailman3/lists/python-dev.python.org/ Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/SMN5GZHGURK2AQKTBES5Z6XLWPDUBNB6/ Code of Conduct: http://python.org/psf/codeofconduct/