On Tue, Jun 23, 2020 at 3:06 PM Emily Bowman <silverback...@gmail.com>
wrote:

> Can you have case (x,x): ? I haven't tried the implementation, but it's
> not addressed in the PEP that I see, and if that's legal, then _ is
> effectively just a style choice, rather than a functional one, and there's
> no reason it shouldn't also be a named match.
>

Good question. It's explicitly forbidden by the PEP, in the "Name pattern"
section:

While matching against each case clause, a name may be bound at most
once, having two name patterns with coinciding names is an error. An
exception is made for the special single underscore (``_``) name; in
patterns, it's a wildcard that *never* binds::

  match data:
      case [x, x]:  # Error!
          ...
      case [_, _]:
          print("Some pair")
          print(_)  # Error!

Note: one can still match on a collection with equal items using `guards`_.
Also, ``[x, y] | Point(x, y)`` is a legal pattern because the two
alternatives are never matched at the same time.

I should add that if you want to check for two values in different
positions being equal, you need to use a guard:

    match data:
        case [x, y] if x == y:
            print("Two equal values")



On Tue, Jun 23, 2020 at 12:11 PM Brett Cannon <br...@python.org> wrote:

> I will say that trying to follow
> https://github.com/python/peps/blob/master/pep-0622.rst#runtime-specification
> was really hard. Any chance of getting some pseudo-code that shows how a
> match is performed? Otherwise all of that wording tries so hard to be a
> spec that I found it hard to follow in my head in how things function.
>

Sorry about that. This section was subject to heavy editing recently and
lost clarity. I will try to make it better! Writing it as pseudo code will
take a little time, but I will give it a try.


> For instance, "When __match_args__ is missing (as is the default) or None,
> a single positional sub-pattern is allowed to be passed to the call" is
> really misleading as it seems that a "sub-pattern" in this case is just
> going to be a constant like `[1, 2, 3]`. Otherwise how does `["<"|">"]` or
> `[1, 2, *_]` get represented as a "single positional sub-pattern" (if
> either of those examples is possible)? The use of the term "sub-pattern"
> feels misleading because while you may consider even constant patterns a
> "pattern", going that generic feels like any pattern should fit in that
> definition when in fact it seems to only be an object where a direct
> equality check is done.
>
> It seems the way things work is basically:
>
> 1. `__match__(obj)` returns a proxy object to have Python match against;
> it is passed in the thing that `match` is running against, returning `None`
> if it know there's no chance a match will work
> 2. If `__match_args__` is present, then it is used to map positional
> arguments in the pattern to attributes on the proxy object
> 3. From there the `match` functionality does a bunch of comparisons
> against attributes on the proxy object to see if the match works
>
> Is that right? That suggests all the work in implementing this for objects
> is coming up with a way to serialize an object to a proxy that makes
> pattern matching possible.
>

Yes, that's right, and the protocol was defined carefully so that the
author of __match__ doesn't have to do any pattern matching -- all they
have to do is produce an object that has the right attributes, and the
interpreter does the rest. Note that it is __match__'s responsibility to
check isinstance()! This is because __match__ may not want to use
isinstance() but instead check for the presence of certain attributes --
IOW, the class pattern supports duck typing! (This was a little easter egg.
:-)


> One thing I see mentioned in examples but not in the `__match__`
> definitions is how mappings work. Are you using `__match_args__` to map
> keys to attributes? Or are you using `__getitem__` and that just isn't
> directly mentioned? Otherwise the section on how `__match__` is used only
> mentioned attributes and never talks about keys.
>

Oh, __match__ is *only* used for class patterns. Mapping patterns are done
differently. They don't use __getitem__ exactly -- the PEP says

Matched key-value pairs must already be present in the mapping, and not
created
on-the-fly by ``__missing__`` or ``__getitem__``.  For example,
``collections.defaultdict`` instances will only match patterns with keys
that
were already present when the ``match`` block was entered.

You shouldn't try to depend on exactly what methods will be called -- you
should just faithfully implement the Mapping protocol.

-- 
--Guido van Rossum (python.org/~guido)
*Pronouns: he/him **(why is my pronoun here?)*
<http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/>
_______________________________________________
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/N7USX5OB2NEPO25JLTMTI4SUQ2CB7WLY/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to