From c029c02e36bb661c7502ca02af8a5fbb5c03a0ce Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 30 Mar 2021 23:30:43 +0100 Subject: [PATCH] PEP 653: Fix example. Use get(key, sentinel) instead of __getitem__(key) for mappings. (#1902) --- pep-0653.rst | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/pep-0653.rst b/pep-0653.rst index c2fc756eb..dbf06cc58 100644 --- a/pep-0653.rst +++ b/pep-0653.rst @@ -53,7 +53,7 @@ By allowing classes to choose which kinds of pattern they match, other classes c For example, using ``sympy``, we might want to write:: # a*a == a**2 - case Mul(args=[a, b]) if a == b: + case Mul(args=[Symbol(a), Symbol(b)]) if a == b: return Pow(a, 2) Which requires the sympy class ``Symbol`` to "self" match. @@ -273,14 +273,16 @@ A pattern not including a double-star pattern:: translates to:: + $sentinel = object() $kind = type($value).__match_container__ if $kind & MATCH_MAPPING == 0: FAIL - if not $value.keys() >= $KEYWORD_PATTERNS.keys(): - FAIL # $KEYWORD_PATTERNS is a meta-variable mapping names to variables. for $KEYWORD in $KEYWORD_PATTERNS: - $KEYWORD_PATTERNS[$KEYWORD] = $value[QUOTE($KEYWORD)] + $tmp = $value.get(QUOTE($KEYWORD), $sentinel) + if $tmp is $sentinel: + FAIL + $KEYWORD_PATTERNS[$KEYWORD] = $tmp Example: [4]_ @@ -293,10 +295,10 @@ translates to:: $kind = type($value).__match_container__ if $kind & MATCH_MAPPING == 0: FAIL - if not $value.keys() >= $KEYWORD_PATTERNS.keys(): - FAIL: # $KEYWORD_PATTERNS is a meta-variable mapping names to variables. $tmp = dict($value) + if not $tmp.keys() >= $KEYWORD_PATTERNS.keys(): + FAIL: for $KEYWORD in $KEYWORD_PATTERNS: $KEYWORD_PATTERNS[$KEYWORD] = $tmp.pop(QUOTE($KEYWORD)) $DOUBLE_STARRED_PATTERN = $tmp @@ -502,15 +504,14 @@ on the naive implementation. When performing matching, implementations are allowed to treat the following functions and methods as pure: -For any class supporting ``MATCH_SEQUENCE`` or ``MATCH_MAPPING``:: +For any class supporting ``MATCH_SEQUENCE``:: * ``cls.__len__()`` * ``cls.__getitem__()`` For any class supporting ``MATCH_MAPPING``:: -* ``cls.keys()`` -* ``cls.__contains__()`` +* ``cls.get()`` (Two argument form only) Implementations are allowed to make the following assumptions: @@ -519,6 +520,8 @@ Implementations are allowed to make the following assumptions: * Reading any of ``__match_container__``, ``__match_class__`` or ``__match_args__`` is a pure operation, and may be cached. * Sequences, that is any class for which ``__match_container__&MATCH_SEQUENCE`` is not zero, are not modified by iteration, subscripting or calls to ``len()``. Consequently, those operations can be freely substituted for each other where they would be equivalent when applied to an immutable sequence. +* Mappings, that is any class for which ``__match_container__&MATCH_MAPPING`` is not zero, will not capture the second argument of the ``get()`` method. + So, the ``$sentinel`` value may be freely re-used. In fact, implementations are encouraged to make these assumptions, as it is likely to result in signficantly better performance. @@ -779,10 +782,14 @@ translates to:: $kind = type($value).__match_container__ if $kind & MATCH_MAPPING == 0: FAIL - if $value.keys() != {"x", "y"}: + $tmp = $value.get("x", $sentinel) + if $tmp is $sentinel: FAIL - x = $value["x"] - y = $value["y"] + x = $tmp + $tmp = $value.get("y", $sentinel) + if $tmp is $sentinel: + FAIL + y = $tmp if not x > 2: FAIL @@ -797,9 +804,9 @@ translates to:: $kind = type($value).__match_container__ if $kind & MATCH_MAPPING == 0: FAIL - if not $value.keys() >= {"x", "y"}: - FAIL $tmp = dict($value) + if not $tmp.keys() >= {"x", "y"}: + FAIL x = $tmp.pop("x") y = $tmp.pop("y") z = $tmp