PEP 622: Updates from Python-Dev (#1472)
In particular __match_args__ is simplified and the default processing only applies to certain built-in types.
This commit is contained in:
parent
c49bcbb1a0
commit
a106177241
45
pep-0622.rst
45
pep-0622.rst
|
@ -142,10 +142,9 @@ A simplified, approximate grammar for the proposed syntax is::
|
|||
pattern: NAME ':=' or_pattern | or_pattern
|
||||
or_pattern: closed_pattern ('|' closed_pattern)*
|
||||
closed_pattern:
|
||||
| name_pattern
|
||||
| literal_pattern
|
||||
| name_pattern
|
||||
| constant_pattern
|
||||
| group_pattern
|
||||
| sequence_pattern
|
||||
| mapping_pattern
|
||||
| class_pattern
|
||||
|
@ -496,7 +495,7 @@ guard succeeds. So this will work::
|
|||
|
||||
values = [0]
|
||||
|
||||
match value:
|
||||
match values:
|
||||
case [x] if x:
|
||||
... # This is not executed
|
||||
case _:
|
||||
|
@ -571,26 +570,16 @@ The procedure is as following:
|
|||
sub-patterns succeed, the overall class pattern match succeeds.
|
||||
|
||||
* If there are match-by-position items and the class has a
|
||||
``__match_args__`` which is not ``None``, the item at position ``i``
|
||||
``__match_args__``, the item at position ``i``
|
||||
is matched against the value looked up by attribute
|
||||
``__match_args__[i]``. For example, a pattern ``Point2D(5, 8)``,
|
||||
where ``Point2D.__match_args__ == ["x", "y"]``, is translated
|
||||
(approximately) into ``obj.x == 5 and obj.y == 8``.
|
||||
|
||||
* When ``__match_args__`` is missing (as is the default) or ``None``, a single
|
||||
positional sub-pattern is allowed to be passed to the call. Rather than being
|
||||
matched against any particular attribute on the proxy, it is instead matched
|
||||
against the proxy itself. This creates default behavior that is useful and
|
||||
intuitive for most objects:
|
||||
|
||||
* ``bool(False)`` matches ``False`` (but not ``0``).
|
||||
* ``tuple((0, 1, 2))`` matches ``(0, 1, 2)`` (but not ``[0, 1, 2]``).
|
||||
* ``int(i)`` matches any ``int`` and binds it to the name ``i``.
|
||||
|
||||
* If there are more positional items than the length of ``__match_args__``, an
|
||||
``ImpossibleMatchError`` is raised.
|
||||
|
||||
* If the ``__match_args__`` attribute is absent on the matched class or ``None``,
|
||||
* If the ``__match_args__`` attribute is absent on the matched class,
|
||||
but more than one positional item appears in a match,
|
||||
``ImpossibleMatchError`` is also raised. We don't fall back on
|
||||
using ``__slots__`` or ``__annotations__`` -- "In the face of ambiguity,
|
||||
|
@ -602,18 +591,30 @@ The procedure is as following:
|
|||
two cases are distinguished:
|
||||
|
||||
* If an attribute is missing on the proxy and the class being matched
|
||||
has no ``__match_args__`` attribute (or it is ``None``), the match
|
||||
has no ``__match_args__`` attribute, the match
|
||||
fails. This allows one to write ``case object(name=_)`` to
|
||||
implement a check for the presence of a given attribute, or ``case
|
||||
object(name=var)`` to check for its presence and extract its value.
|
||||
|
||||
* If an attribute is missing and the class has a ``__match_args__``
|
||||
which is not ``None``, the match fails if the attribute name is in
|
||||
* If an attribute is missing and the class has a ``__match_args__``,
|
||||
the match fails if the attribute name is in
|
||||
``__match_args__``, else the match raises ``ImpossibleMatchError``.
|
||||
|
||||
Such a protocol favors simplicity of implementation over flexibility and
|
||||
performance. For other considered alternatives, see `rejected ideas`_.
|
||||
|
||||
For the most commonly-matched built-in types (specifically: ``bool``,
|
||||
``bytearray``, ``bytes``, ``complex``, ``dict``, ``float``,
|
||||
``frozenset``, ``int``, ``list``, ``set``, ``str``, ``tuple``, and
|
||||
``type``), a single positional sub-pattern is allowed to be passed to
|
||||
the call. Rather than being matched against any particular attribute
|
||||
on the proxy, it is instead matched against the proxy itself. This
|
||||
creates behavior that is useful and intuitive for these objects:
|
||||
|
||||
* ``bool(False)`` matches ``False`` (but not ``0``).
|
||||
* ``tuple((0, 1, 2))`` matches ``(0, 1, 2)`` (but not ``[0, 1, 2]``).
|
||||
* ``int(i)`` matches any ``int`` and binds it to the name ``i``.
|
||||
|
||||
|
||||
Result value of ``__match__()``
|
||||
-------------------------------
|
||||
|
@ -660,7 +661,7 @@ Special attribute ``__match_args__``
|
|||
|
||||
The ``__match_args__`` attribute complements the ``__match__`` method and is
|
||||
always looked up on the same class as the ``__match__`` method.
|
||||
``__match_args__``, if it is present and not ``None``, must be a list or
|
||||
``__match_args__``, if it is present, must be a list or
|
||||
tuple of strings naming the allowed positional arguments.
|
||||
|
||||
|
||||
|
@ -682,11 +683,11 @@ a class wants to disallow pattern matching against itself, it should define
|
|||
``__match__ = None``. This will cause an exception when trying to match
|
||||
against such a class.
|
||||
|
||||
The above implementation means that by default only match-by-name and a single
|
||||
positional match by value against the proxy will work,
|
||||
The above implementation means that by default only match-by-name will
|
||||
work,
|
||||
and classes should define ``__match_args__`` (e.g. as a class
|
||||
attribute) if they would like to support match-by-position. Additionally,
|
||||
dataclasses will support match-by-position out of the box. See below for more
|
||||
dataclasses and named tuples will support match-by-position out of the box. See below for more
|
||||
details.
|
||||
|
||||
Finally, all attributes are exposed for matching, if a class wants to hide
|
||||
|
|
Loading…
Reference in New Issue