mirror of https://github.com/python/peps
1044 lines
71 KiB
HTML
1044 lines
71 KiB
HTML
|
||
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<meta name="color-scheme" content="light dark">
|
||
<title>PEP 653 – Precise Semantics for Pattern Matching | peps.python.org</title>
|
||
<link rel="shortcut icon" href="../_static/py.png">
|
||
<link rel="canonical" href="https://peps.python.org/pep-0653/">
|
||
<link rel="stylesheet" href="../_static/style.css" type="text/css">
|
||
<link rel="stylesheet" href="../_static/mq.css" type="text/css">
|
||
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" media="(prefers-color-scheme: light)" id="pyg-light">
|
||
<link rel="stylesheet" href="../_static/pygments_dark.css" type="text/css" media="(prefers-color-scheme: dark)" id="pyg-dark">
|
||
<link rel="alternate" type="application/rss+xml" title="Latest PEPs" href="https://peps.python.org/peps.rss">
|
||
<meta property="og:title" content='PEP 653 – Precise Semantics for Pattern Matching | peps.python.org'>
|
||
<meta property="og:type" content="website">
|
||
<meta property="og:url" content="https://peps.python.org/pep-0653/">
|
||
<meta property="og:site_name" content="Python Enhancement Proposals (PEPs)">
|
||
<meta property="og:image" content="https://peps.python.org/_static/og-image.png">
|
||
<meta property="og:image:alt" content="Python PEPs">
|
||
<meta property="og:image:width" content="200">
|
||
<meta property="og:image:height" content="200">
|
||
<meta name="description" content="Python Enhancement Proposals (PEPs)">
|
||
<meta name="theme-color" content="#3776ab">
|
||
</head>
|
||
<body>
|
||
|
||
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
|
||
<symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all">
|
||
<title>Following system colour scheme</title>
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<circle cx="12" cy="12" r="9"></circle>
|
||
<path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path>
|
||
</svg>
|
||
</symbol>
|
||
<symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all">
|
||
<title>Selected dark colour scheme</title>
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path>
|
||
</svg>
|
||
</symbol>
|
||
<symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all">
|
||
<title>Selected light colour scheme</title>
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
|
||
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<circle cx="12" cy="12" r="5"></circle>
|
||
<line x1="12" y1="1" x2="12" y2="3"></line>
|
||
<line x1="12" y1="21" x2="12" y2="23"></line>
|
||
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
|
||
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
|
||
<line x1="1" y1="12" x2="3" y2="12"></line>
|
||
<line x1="21" y1="12" x2="23" y2="12"></line>
|
||
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
|
||
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
|
||
</svg>
|
||
</symbol>
|
||
</svg>
|
||
<script>
|
||
|
||
document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto"
|
||
</script>
|
||
<section id="pep-page-section">
|
||
<header>
|
||
<h1>Python Enhancement Proposals</h1>
|
||
<ul class="breadcrumbs">
|
||
<li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> » </li>
|
||
<li><a href="../pep-0000/">PEP Index</a> » </li>
|
||
<li>PEP 653</li>
|
||
</ul>
|
||
<button id="colour-scheme-cycler" onClick="setColourScheme(nextColourScheme())">
|
||
<svg aria-hidden="true" class="colour-scheme-icon-when-auto"><use href="#svg-sun-half"></use></svg>
|
||
<svg aria-hidden="true" class="colour-scheme-icon-when-dark"><use href="#svg-moon"></use></svg>
|
||
<svg aria-hidden="true" class="colour-scheme-icon-when-light"><use href="#svg-sun"></use></svg>
|
||
<span class="visually-hidden">Toggle light / dark / auto colour theme</span>
|
||
</button>
|
||
</header>
|
||
<article>
|
||
<section id="pep-content">
|
||
<h1 class="page-title">PEP 653 – Precise Semantics for Pattern Matching</h1>
|
||
<dl class="rfc2822 field-list simple">
|
||
<dt class="field-odd">Author<span class="colon">:</span></dt>
|
||
<dd class="field-odd">Mark Shannon <mark at hotpy.org></dd>
|
||
<dt class="field-even">Status<span class="colon">:</span></dt>
|
||
<dd class="field-even"><abbr title="Proposal under active discussion and revision">Draft</abbr></dd>
|
||
<dt class="field-odd">Type<span class="colon">:</span></dt>
|
||
<dd class="field-odd"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd>
|
||
<dt class="field-even">Created<span class="colon">:</span></dt>
|
||
<dd class="field-even">09-Feb-2021</dd>
|
||
<dt class="field-odd">Post-History<span class="colon">:</span></dt>
|
||
<dd class="field-odd">18-Feb-2021</dd>
|
||
</dl>
|
||
<hr class="docutils" />
|
||
<section id="contents">
|
||
<details><summary>Table of Contents</summary><ul class="simple">
|
||
<li><a class="reference internal" href="#abstract">Abstract</a></li>
|
||
<li><a class="reference internal" href="#motivation">Motivation</a><ul>
|
||
<li><a class="reference internal" href="#precise-semantics">Precise semantics</a></li>
|
||
<li><a class="reference internal" href="#improved-control-over-class-matching">Improved control over class matching</a></li>
|
||
<li><a class="reference internal" href="#robustness">Robustness</a></li>
|
||
<li><a class="reference internal" href="#efficient-implementation">Efficient implementation</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#rationale">Rationale</a></li>
|
||
<li><a class="reference internal" href="#specification">Specification</a><ul>
|
||
<li><a class="reference internal" href="#additions-to-the-object-model">Additions to the object model</a></li>
|
||
<li><a class="reference internal" href="#semantics-of-the-matching-process">Semantics of the matching process</a><ul>
|
||
<li><a class="reference internal" href="#preamble">Preamble</a></li>
|
||
<li><a class="reference internal" href="#capture-patterns">Capture patterns</a></li>
|
||
<li><a class="reference internal" href="#wildcard-patterns">Wildcard patterns</a></li>
|
||
<li><a class="reference internal" href="#literal-patterns">Literal Patterns</a></li>
|
||
<li><a class="reference internal" href="#value-patterns">Value Patterns</a></li>
|
||
<li><a class="reference internal" href="#sequence-patterns">Sequence Patterns</a></li>
|
||
<li><a class="reference internal" href="#mapping-patterns">Mapping Patterns</a></li>
|
||
<li><a class="reference internal" href="#class-patterns">Class Patterns</a></li>
|
||
<li><a class="reference internal" href="#nested-patterns">Nested patterns</a></li>
|
||
<li><a class="reference internal" href="#guards">Guards</a></li>
|
||
<li><a class="reference internal" href="#non-conforming-special-attributes">Non-conforming special attributes</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#values-of-the-special-attributes-for-classes-in-the-standard-library">Values of the special attributes for classes in the standard library</a></li>
|
||
<li><a class="reference internal" href="#legal-optimizations">Legal optimizations</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#security-implications">Security Implications</a></li>
|
||
<li><a class="reference internal" href="#implementation">Implementation</a><ul>
|
||
<li><a class="reference internal" href="#possible-optimizations">Possible optimizations</a><ul>
|
||
<li><a class="reference internal" href="#splitting-evaluation-into-lanes">Splitting evaluation into lanes</a></li>
|
||
<li><a class="reference internal" href="#id9">Sequence patterns</a></li>
|
||
<li><a class="reference internal" href="#id10">Mapping patterns</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#summary-of-differences-between-this-pep-and-pep-634">Summary of differences between this PEP and PEP 634</a></li>
|
||
<li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul>
|
||
<li><a class="reference internal" href="#using-attributes-from-the-instance-s-dictionary">Using attributes from the instance’s dictionary</a></li>
|
||
<li><a class="reference internal" href="#lookup-of-match-args-on-the-subject-not-the-pattern">Lookup of <code class="docutils literal notranslate"><span class="pre">__match_args__</span></code> on the subject not the pattern</a></li>
|
||
<li><a class="reference internal" href="#combining-match-class-and-match-container-into-a-single-value">Combining <code class="docutils literal notranslate"><span class="pre">__match_class__</span></code> and <code class="docutils literal notranslate"><span class="pre">__match_container__</span></code> into a single value</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#deferred-ideas">Deferred Ideas</a><ul>
|
||
<li><a class="reference internal" href="#having-a-separate-value-to-reject-all-class-matches">Having a separate value to reject all class matches</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#code-examples">Code examples</a></li>
|
||
<li><a class="reference internal" href="#copyright">Copyright</a></li>
|
||
</ul>
|
||
</details></section>
|
||
<section id="abstract">
|
||
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
|
||
<p>This PEP proposes a semantics for pattern matching that respects the general concept of <a class="pep reference internal" href="../pep-0634/" title="PEP 634 – Structural Pattern Matching: Specification">PEP 634</a>,
|
||
but is more precise, easier to reason about, and should be faster.</p>
|
||
<p>The object model will be extended with two special (dunder) attributes, <code class="docutils literal notranslate"><span class="pre">__match_container__</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">__match_class__</span></code>, in addition to the <code class="docutils literal notranslate"><span class="pre">__match_args__</span></code> attribute from <a class="pep reference internal" href="../pep-0634/" title="PEP 634 – Structural Pattern Matching: Specification">PEP 634</a>, to support pattern matching.
|
||
Both of these new attributes must be integers and <code class="docutils literal notranslate"><span class="pre">__match_args__</span></code> is required to be a tuple of unique strings.</p>
|
||
<p>With this PEP:</p>
|
||
<ul class="simple">
|
||
<li>The semantics of pattern matching will be clearer, so that patterns are easier to reason about.</li>
|
||
<li>It will be possible to implement pattern matching in a more efficient fashion.</li>
|
||
<li>Pattern matching will be more usable for complex classes, by allowing classes some more control over which patterns they match.</li>
|
||
</ul>
|
||
</section>
|
||
<section id="motivation">
|
||
<h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2>
|
||
<p>Pattern matching in Python, as described in <a class="pep reference internal" href="../pep-0634/" title="PEP 634 – Structural Pattern Matching: Specification">PEP 634</a>, is to be added to Python 3.10.
|
||
Unfortunately, <a class="pep reference internal" href="../pep-0634/" title="PEP 634 – Structural Pattern Matching: Specification">PEP 634</a> is not as precise about the semantics as it could be,
|
||
nor does it allow classes sufficient control over how they match patterns.</p>
|
||
<section id="precise-semantics">
|
||
<h3><a class="toc-backref" href="#precise-semantics" role="doc-backlink">Precise semantics</a></h3>
|
||
<p><a class="pep reference internal" href="../pep-0634/" title="PEP 634 – Structural Pattern Matching: Specification">PEP 634</a> explicitly includes a section on undefined behavior.
|
||
Large amounts of undefined behavior may be acceptable in a language like C,
|
||
but in Python it should be kept to a minimum.
|
||
Pattern matching in Python can be defined more precisely without losing expressiveness or performance.</p>
|
||
</section>
|
||
<section id="improved-control-over-class-matching">
|
||
<h3><a class="toc-backref" href="#improved-control-over-class-matching" role="doc-backlink">Improved control over class matching</a></h3>
|
||
<p><a class="pep reference internal" href="../pep-0634/" title="PEP 634 – Structural Pattern Matching: Specification">PEP 634</a> delegates the decision over whether a class is a sequence or mapping to <code class="docutils literal notranslate"><span class="pre">collections.abc</span></code>.
|
||
Not all classes that could be considered sequences are registered as subclasses of <code class="docutils literal notranslate"><span class="pre">collections.abc.Sequence</span></code>.
|
||
This PEP allows them to match sequence patterns, without the full <code class="docutils literal notranslate"><span class="pre">collections.abc.Sequence</span></code> machinery.</p>
|
||
<p><a class="pep reference internal" href="../pep-0634/" title="PEP 634 – Structural Pattern Matching: Specification">PEP 634</a> privileges some builtin classes with a special form of matching, the “self” match.
|
||
For example the pattern <code class="docutils literal notranslate"><span class="pre">list(x)</span></code> matches a list and assigns the list to <code class="docutils literal notranslate"><span class="pre">x</span></code>.
|
||
By allowing classes to choose which kinds of pattern they match, other classes can use this form as well.</p>
|
||
<p>For example, using <code class="docutils literal notranslate"><span class="pre">sympy</span></code>, we might want to write:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># a*a == a**2</span>
|
||
<span class="k">case</span> <span class="n">Mul</span><span class="p">(</span><span class="n">args</span><span class="o">=</span><span class="p">[</span><span class="n">Symbol</span><span class="p">(</span><span class="n">a</span><span class="p">),</span> <span class="n">Symbol</span><span class="p">(</span><span class="n">b</span><span class="p">)])</span> <span class="k">if</span> <span class="n">a</span> <span class="o">==</span> <span class="n">b</span><span class="p">:</span>
|
||
<span class="k">return</span> <span class="n">Pow</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Which requires the sympy class <code class="docutils literal notranslate"><span class="pre">Symbol</span></code> to “self” match.
|
||
For <code class="docutils literal notranslate"><span class="pre">sympy</span></code> to support this pattern with <a class="pep reference internal" href="../pep-0634/" title="PEP 634 – Structural Pattern Matching: Specification">PEP 634</a> is possible, but a bit tricky.
|
||
With this PEP it can be implemented very easily <a class="footnote-reference brackets" href="#id12" id="id1">[1]</a>.</p>
|
||
</section>
|
||
<section id="robustness">
|
||
<h3><a class="toc-backref" href="#robustness" role="doc-backlink">Robustness</a></h3>
|
||
<p>With this PEP, access to attributes during pattern matching becomes well defined and deterministic.
|
||
This makes pattern matching less error prone when matching objects with hidden side effects, such as object-relational mappers.
|
||
Objects will have more control over their own deconstruction, which can help prevent unintended consequences should attribute access have side-effects.</p>
|
||
<p><a class="pep reference internal" href="../pep-0634/" title="PEP 634 – Structural Pattern Matching: Specification">PEP 634</a> relies on the <code class="docutils literal notranslate"><span class="pre">collections.abc</span></code> module when determining which patterns a value can match, implicitly importing it if necessary.
|
||
This PEP will eliminate surprising import errors and misleading audit events from those imports.</p>
|
||
</section>
|
||
<section id="efficient-implementation">
|
||
<h3><a class="toc-backref" href="#efficient-implementation" role="doc-backlink">Efficient implementation</a></h3>
|
||
<p>The semantics proposed in this PEP will allow efficient implementation, partly as a result of having precise semantics
|
||
and partly from using the object model.</p>
|
||
<p>With precise semantics, it is possible to reason about what code transformations are correct,
|
||
and thus apply optimizations effectively.</p>
|
||
<p>Because the object model is a core part of Python, implementations already handle special attribute lookup efficiently.
|
||
Looking up a special attribute is much faster than performing a subclass test on an abstract base class.</p>
|
||
</section>
|
||
</section>
|
||
<section id="rationale">
|
||
<h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2>
|
||
<p>The object model and special methods are at the core of the Python language. Consequently,
|
||
implementations support them well.
|
||
Using special attributes for pattern matching allows pattern matching to be implemented in a way that
|
||
integrates well with the rest of the implementation, and is thus easier to maintain and is likely to perform better.</p>
|
||
<p>A match statement performs a sequence of pattern matches. In general, matching a pattern has three parts:</p>
|
||
<ol class="arabic simple">
|
||
<li>Can the value match this kind of pattern?</li>
|
||
<li>When deconstructed, does the value match this particular pattern?</li>
|
||
<li>Is the guard true?</li>
|
||
</ol>
|
||
<p>To determine whether a value can match a particular kind of pattern, we add the <code class="docutils literal notranslate"><span class="pre">__match_container__</span></code>
|
||
and <code class="docutils literal notranslate"><span class="pre">__match_class__</span></code> attributes.
|
||
This allows the kind of a value to be determined in a efficient fashion.</p>
|
||
</section>
|
||
<section id="specification">
|
||
<h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2>
|
||
<section id="additions-to-the-object-model">
|
||
<h3><a class="toc-backref" href="#additions-to-the-object-model" role="doc-backlink">Additions to the object model</a></h3>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">__match_container__</span></code> and <code class="docutils literal notranslate"><span class="pre">__match_class__</span></code> attributes will be added to <code class="docutils literal notranslate"><span class="pre">object</span></code>.
|
||
<code class="docutils literal notranslate"><span class="pre">__match_container__</span></code> should be overridden by classes that want to match mapping or sequence patterns.
|
||
<code class="docutils literal notranslate"><span class="pre">__match_class__</span></code> should be overridden by classes that want to change the default behavior when matching class patterns.</p>
|
||
<p><code class="docutils literal notranslate"><span class="pre">__match_container__</span></code> must be an integer and should be exactly one of these:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="mi">0</span>
|
||
<span class="n">MATCH_SEQUENCE</span> <span class="o">=</span> <span class="mi">1</span>
|
||
<span class="n">MATCH_MAPPING</span> <span class="o">=</span> <span class="mi">2</span>
|
||
</pre></div>
|
||
</div>
|
||
<p><code class="docutils literal notranslate"><span class="pre">MATCH_SEQUENCE</span></code> is used to indicate that instances of the class can match sequence patterns.</p>
|
||
<p><code class="docutils literal notranslate"><span class="pre">MATCH_MAPPING</span></code> is used to indicate that instances of the class can match mapping patterns.</p>
|
||
<p><code class="docutils literal notranslate"><span class="pre">__match_class__</span></code> must be an integer and should be exactly one of these:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="mi">0</span>
|
||
<span class="n">MATCH_SELF</span> <span class="o">=</span> <span class="mi">8</span>
|
||
</pre></div>
|
||
</div>
|
||
<p><code class="docutils literal notranslate"><span class="pre">MATCH_SELF</span></code> is used to indicate that for a single positional argument class pattern, the subject will be used and not deconstructed.</p>
|
||
<div class="admonition note">
|
||
<p class="admonition-title">Note</p>
|
||
<p>In the rest of this document, we will refer to the above values by name only.
|
||
Symbolic constants will be provided both for Python and C, and the values will
|
||
never be changed.</p>
|
||
</div>
|
||
<p><code class="docutils literal notranslate"><span class="pre">object</span></code> will have the following values for the special attributes:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">__match_container__</span> <span class="o">=</span> <span class="mi">0</span>
|
||
<span class="n">__match_class__</span><span class="o">=</span> <span class="mi">0</span>
|
||
<span class="n">__match_args__</span> <span class="o">=</span> <span class="p">()</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>These special attributes will be inherited as normal.</p>
|
||
<p>If <code class="docutils literal notranslate"><span class="pre">__match_args__</span></code> is overridden, then it is required to hold a tuple of unique strings. It may be empty.</p>
|
||
<div class="admonition note">
|
||
<p class="admonition-title">Note</p>
|
||
<p><code class="docutils literal notranslate"><span class="pre">__match_args__</span></code> will be automatically generated for dataclasses and named tuples, as specified in <a class="pep reference internal" href="../pep-0634/" title="PEP 634 – Structural Pattern Matching: Specification">PEP 634</a>.</p>
|
||
</div>
|
||
<p>The pattern matching implementation is <em>not</em> required to check that any of these attributes behave as specified.
|
||
If the value of <code class="docutils literal notranslate"><span class="pre">__match_container__</span></code>, <code class="docutils literal notranslate"><span class="pre">__match_class__</span></code> or <code class="docutils literal notranslate"><span class="pre">__match_args__</span></code> is not as specified, then
|
||
the implementation may raise any exception, or match the wrong pattern.
|
||
Of course, implementations are free to check these properties and provide meaningful error messages if they can do so efficiently.</p>
|
||
</section>
|
||
<section id="semantics-of-the-matching-process">
|
||
<h3><a class="toc-backref" href="#semantics-of-the-matching-process" role="doc-backlink">Semantics of the matching process</a></h3>
|
||
<p>In the following, all variables of the form <code class="docutils literal notranslate"><span class="pre">$var</span></code> are temporary variables and are not visible to the Python program.
|
||
They may be visible via introspection, but that is an implementation detail and should not be relied on.
|
||
The pseudo-statement <code class="docutils literal notranslate"><span class="pre">FAIL</span></code> is used to signify that matching failed for this pattern and that matching should move to the next pattern.
|
||
If control reaches the end of the translation without reaching a <code class="docutils literal notranslate"><span class="pre">FAIL</span></code>, then it has matched, and following patterns are ignored.</p>
|
||
<p>Variables of the form <code class="docutils literal notranslate"><span class="pre">$ALL_CAPS</span></code> are meta-variables holding a syntactic element, they are not normal variables.
|
||
So, <code class="docutils literal notranslate"><span class="pre">$VARS</span> <span class="pre">=</span> <span class="pre">$items</span></code> is not an assignment of <code class="docutils literal notranslate"><span class="pre">$items</span></code> to <code class="docutils literal notranslate"><span class="pre">$VARS</span></code>,
|
||
but an unpacking of <code class="docutils literal notranslate"><span class="pre">$items</span></code> into the variables that <code class="docutils literal notranslate"><span class="pre">$VARS</span></code> holds.
|
||
For example, with the abstract syntax <code class="docutils literal notranslate"><span class="pre">case</span> <span class="pre">[$VARS]:</span></code>, and the concrete syntax <code class="docutils literal notranslate"><span class="pre">case[a,</span> <span class="pre">b]:</span></code> then <code class="docutils literal notranslate"><span class="pre">$VARS</span></code> would hold the variables <code class="docutils literal notranslate"><span class="pre">(a,</span> <span class="pre">b)</span></code>,
|
||
not the values of those variables.</p>
|
||
<p>The pseudo-function <code class="docutils literal notranslate"><span class="pre">QUOTE</span></code> takes a variable and returns the name of that variable.
|
||
For example, if the meta-variable <code class="docutils literal notranslate"><span class="pre">$VAR</span></code> held the variable <code class="docutils literal notranslate"><span class="pre">foo</span></code> then <code class="docutils literal notranslate"><span class="pre">QUOTE($VAR)</span> <span class="pre">==</span> <span class="pre">"foo"</span></code>.</p>
|
||
<p>All additional code listed below that is not present in the original source will not trigger line events, conforming to <a class="pep reference internal" href="../pep-0626/" title="PEP 626 – Precise line numbers for debugging and other tools.">PEP 626</a>.</p>
|
||
<section id="preamble">
|
||
<h4><a class="toc-backref" href="#preamble" role="doc-backlink">Preamble</a></h4>
|
||
<p>Before any patterns are matched, the expression being matched is evaluated:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">expr</span><span class="p">:</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>translates to:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>$value = expr
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="capture-patterns">
|
||
<h4><a class="toc-backref" href="#capture-patterns" role="doc-backlink">Capture patterns</a></h4>
|
||
<p>Capture patterns always match, so the irrefutable match:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">case</span> <span class="n">capture_var</span><span class="p">:</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>translates to:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>capture_var = $value
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="wildcard-patterns">
|
||
<h4><a class="toc-backref" href="#wildcard-patterns" role="doc-backlink">Wildcard patterns</a></h4>
|
||
<p>Wildcard patterns always match, so:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">case</span><span class="w"> </span><span class="k">_</span><span class="p">:</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>translates to:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># No code -- Automatically matches</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="literal-patterns">
|
||
<h4><a class="toc-backref" href="#literal-patterns" role="doc-backlink">Literal Patterns</a></h4>
|
||
<p>The literal pattern:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">case</span> <span class="n">LITERAL</span><span class="p">:</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>translates to:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>if $value != LITERAL:
|
||
FAIL
|
||
</pre></div>
|
||
</div>
|
||
<p>except when the literal is one of <code class="docutils literal notranslate"><span class="pre">None</span></code>, <code class="docutils literal notranslate"><span class="pre">True</span></code> or <code class="docutils literal notranslate"><span class="pre">False</span></code> ,
|
||
when it translates to:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>if $value is not LITERAL:
|
||
FAIL
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="value-patterns">
|
||
<h4><a class="toc-backref" href="#value-patterns" role="doc-backlink">Value Patterns</a></h4>
|
||
<p>The value pattern:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">case</span> <span class="n">value</span><span class="o">.</span><span class="n">pattern</span><span class="p">:</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>translates to:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>if $value != value.pattern:
|
||
FAIL
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="sequence-patterns">
|
||
<h4><a class="toc-backref" href="#sequence-patterns" role="doc-backlink">Sequence Patterns</a></h4>
|
||
<p>A pattern not including a star pattern:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>case [$VARS]:
|
||
</pre></div>
|
||
</div>
|
||
<p>translates to:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>$kind = type($value).__match_container__
|
||
if $kind != MATCH_SEQUENCE:
|
||
FAIL
|
||
if len($value) != len($VARS):
|
||
FAIL
|
||
$VARS = $value
|
||
</pre></div>
|
||
</div>
|
||
<p>Example: <a class="footnote-reference brackets" href="#id13" id="id2">[2]</a></p>
|
||
<p>A pattern including a star pattern:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>case [$VARS]
|
||
</pre></div>
|
||
</div>
|
||
<p>translates to:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>$kind = type($value).__match_container__
|
||
if $kind != MATCH_SEQUENCE:
|
||
FAIL
|
||
if len($value) < len($VARS):
|
||
FAIL
|
||
$VARS = $value # Note that $VARS includes a star expression.
|
||
</pre></div>
|
||
</div>
|
||
<p>Example: <a class="footnote-reference brackets" href="#id14" id="id3">[3]</a></p>
|
||
</section>
|
||
<section id="mapping-patterns">
|
||
<h4><a class="toc-backref" href="#mapping-patterns" role="doc-backlink">Mapping Patterns</a></h4>
|
||
<p>A pattern not including a double-star pattern:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>case {$KEYWORD_PATTERNS}:
|
||
</pre></div>
|
||
</div>
|
||
<p>translates to:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>$sentinel = object()
|
||
$kind = type($value).__match_container__
|
||
if $kind != MATCH_MAPPING:
|
||
FAIL
|
||
# $KEYWORD_PATTERNS is a meta-variable mapping names to variables.
|
||
for $KEYWORD in $KEYWORD_PATTERNS:
|
||
$tmp = $value.get(QUOTE($KEYWORD), $sentinel)
|
||
if $tmp is $sentinel:
|
||
FAIL
|
||
$KEYWORD_PATTERNS[$KEYWORD] = $tmp
|
||
</pre></div>
|
||
</div>
|
||
<p>Example: <a class="footnote-reference brackets" href="#id15" id="id4">[4]</a></p>
|
||
<p>A pattern including a double-star pattern:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>case {$KEYWORD_PATTERNS, **$DOUBLE_STARRED_PATTERN}:
|
||
</pre></div>
|
||
</div>
|
||
<p>translates to:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>$kind = type($value).__match_container__
|
||
if $kind != MATCH_MAPPING:
|
||
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
|
||
</pre></div>
|
||
</div>
|
||
<p>Example: <a class="footnote-reference brackets" href="#id16" id="id5">[5]</a></p>
|
||
</section>
|
||
<section id="class-patterns">
|
||
<h4><a class="toc-backref" href="#class-patterns" role="doc-backlink">Class Patterns</a></h4>
|
||
<p>Class pattern with no arguments:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">case</span> <span class="n">ClsName</span><span class="p">():</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>translates to:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>if not isinstance($value, ClsName):
|
||
FAIL
|
||
</pre></div>
|
||
</div>
|
||
<p>Class pattern with a single positional pattern:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>case ClsName($VAR):
|
||
</pre></div>
|
||
</div>
|
||
<p>translates to:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>$kind = type($value).__match_class__
|
||
if $kind == MATCH_SELF:
|
||
if not isinstance($value, ClsName):
|
||
FAIL
|
||
$VAR = $value
|
||
else:
|
||
As other positional-only class pattern
|
||
</pre></div>
|
||
</div>
|
||
<p>Positional-only class pattern:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>case ClsName($VARS):
|
||
</pre></div>
|
||
</div>
|
||
<p>translates to:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>if not isinstance($value, ClsName):
|
||
FAIL
|
||
$attrs = ClsName.__match_args__
|
||
if len($attr) < len($VARS):
|
||
raise TypeError(...)
|
||
try:
|
||
for i, $VAR in enumerate($VARS):
|
||
$VAR = getattr($value, $attrs[i])
|
||
except AttributeError:
|
||
FAIL
|
||
</pre></div>
|
||
</div>
|
||
<p>Example: <a class="footnote-reference brackets" href="#id17" id="id6">[6]</a></p>
|
||
<p>Class patterns with all keyword patterns:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>case ClsName($KEYWORD_PATTERNS):
|
||
</pre></div>
|
||
</div>
|
||
<p>translates to:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>if not isinstance($value, ClsName):
|
||
FAIL
|
||
try:
|
||
for $KEYWORD in $KEYWORD_PATTERNS:
|
||
$tmp = getattr($value, QUOTE($KEYWORD))
|
||
$KEYWORD_PATTERNS[$KEYWORD] = $tmp
|
||
except AttributeError:
|
||
FAIL
|
||
</pre></div>
|
||
</div>
|
||
<p>Example: <a class="footnote-reference brackets" href="#id18" id="id7">[7]</a></p>
|
||
<p>Class patterns with positional and keyword patterns:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>case ClsName($VARS, $KEYWORD_PATTERNS):
|
||
</pre></div>
|
||
</div>
|
||
<p>translates to:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>if not isinstance($value, ClsName):
|
||
FAIL
|
||
$attrs = ClsName.__match_args__
|
||
if len($attr) < len($VARS):
|
||
raise TypeError(...)
|
||
$pos_attrs = $attrs[:len($VARS)]
|
||
try:
|
||
for i, $VAR in enumerate($VARS):
|
||
$VAR = getattr($value, $attrs[i])
|
||
for $KEYWORD in $KEYWORD_PATTERNS:
|
||
$name = QUOTE($KEYWORD)
|
||
if $name in pos_attrs:
|
||
raise TypeError(...)
|
||
$KEYWORD_PATTERNS[$KEYWORD] = getattr($value, $name)
|
||
except AttributeError:
|
||
FAIL
|
||
</pre></div>
|
||
</div>
|
||
<p>Example: <a class="footnote-reference brackets" href="#id19" id="id8">[8]</a></p>
|
||
</section>
|
||
<section id="nested-patterns">
|
||
<h4><a class="toc-backref" href="#nested-patterns" role="doc-backlink">Nested patterns</a></h4>
|
||
<p>The above specification assumes that patterns are not nested. For nested patterns
|
||
the above translations are applied recursively by introducing temporary capture patterns.</p>
|
||
<p>For example, the pattern:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">case</span> <span class="p">[</span><span class="nb">int</span><span class="p">(),</span> <span class="nb">str</span><span class="p">()]:</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>translates to:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>$kind = type($value).__match_class__
|
||
if $kind != MATCH_SEQUENCE:
|
||
FAIL
|
||
if len($value) != 2:
|
||
FAIL
|
||
$value_0, $value_1 = $value
|
||
#Now match on temporary values
|
||
if not isinstance($value_0, int):
|
||
FAIL
|
||
if not isinstance($value_1, str):
|
||
FAIL
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="guards">
|
||
<h4><a class="toc-backref" href="#guards" role="doc-backlink">Guards</a></h4>
|
||
<p>Guards translate to a test following the rest of the translation:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">case</span> <span class="n">pattern</span> <span class="k">if</span> <span class="n">guard</span><span class="p">:</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>translates to:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[</span><span class="n">translation</span> <span class="k">for</span> <span class="n">pattern</span><span class="p">]</span>
|
||
<span class="k">if</span> <span class="ow">not</span> <span class="n">guard</span><span class="p">:</span>
|
||
<span class="n">FAIL</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="non-conforming-special-attributes">
|
||
<h4><a class="toc-backref" href="#non-conforming-special-attributes" role="doc-backlink">Non-conforming special attributes</a></h4>
|
||
<p>All classes should ensure that the the values of <code class="docutils literal notranslate"><span class="pre">__match_container__</span></code>, <code class="docutils literal notranslate"><span class="pre">__match_class__</span></code>
|
||
and <code class="docutils literal notranslate"><span class="pre">__match_args__</span></code> follow the specification.
|
||
Therefore, implementations can assume, without checking, that the following are true:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">__match_container__</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">__match_container__</span> <span class="o">==</span> <span class="n">MATCH_SEQUENCE</span> <span class="ow">or</span> <span class="n">__match_container__</span> <span class="o">==</span> <span class="n">MATCH_MAPPING</span>
|
||
<span class="n">__match_class__</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">or</span> <span class="n">__match_class__</span> <span class="o">==</span> <span class="n">MATCH_SELF</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>and that <code class="docutils literal notranslate"><span class="pre">__match_args__</span></code> is a tuple of unique strings.</p>
|
||
</section>
|
||
</section>
|
||
<section id="values-of-the-special-attributes-for-classes-in-the-standard-library">
|
||
<h3><a class="toc-backref" href="#values-of-the-special-attributes-for-classes-in-the-standard-library" role="doc-backlink">Values of the special attributes for classes in the standard library</a></h3>
|
||
<p>For the core builtin container classes <code class="docutils literal notranslate"><span class="pre">__match_container__</span></code> will be:</p>
|
||
<ul class="simple">
|
||
<li><code class="docutils literal notranslate"><span class="pre">list</span></code>: <code class="docutils literal notranslate"><span class="pre">MATCH_SEQUENCE</span></code></li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">tuple</span></code>: <code class="docutils literal notranslate"><span class="pre">MATCH_SEQUENCE</span></code></li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">dict</span></code>: <code class="docutils literal notranslate"><span class="pre">MATCH_MAPPING</span></code></li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">bytearray</span></code>: 0</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">bytes</span></code>: 0</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">str</span></code>: 0</li>
|
||
</ul>
|
||
<p>Named tuples will have <code class="docutils literal notranslate"><span class="pre">__match_container__</span></code> set to <code class="docutils literal notranslate"><span class="pre">MATCH_SEQUENCE</span></code>.</p>
|
||
<ul class="simple">
|
||
<li>All other standard library classes for which <code class="docutils literal notranslate"><span class="pre">issubclass(cls,</span> <span class="pre">collections.abc.Mapping)</span></code> is true will have <code class="docutils literal notranslate"><span class="pre">__match_container__</span></code> set to <code class="docutils literal notranslate"><span class="pre">MATCH_MAPPING</span></code>.</li>
|
||
<li>All other standard library classes for which <code class="docutils literal notranslate"><span class="pre">issubclass(cls,</span> <span class="pre">collections.abc.Sequence)</span></code> is true will have <code class="docutils literal notranslate"><span class="pre">__match_container__</span></code> set to <code class="docutils literal notranslate"><span class="pre">MATCH_SEQUENCE</span></code>.</li>
|
||
</ul>
|
||
<p>For the following builtin classes <code class="docutils literal notranslate"><span class="pre">__match_class__</span></code> will be set to <code class="docutils literal notranslate"><span class="pre">MATCH_SELF</span></code>:</p>
|
||
<ul class="simple">
|
||
<li><code class="docutils literal notranslate"><span class="pre">bool</span></code></li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">bytearray</span></code></li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">bytes</span></code></li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">float</span></code></li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">frozenset</span></code></li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">int</span></code></li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">set</span></code></li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">str</span></code></li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">list</span></code></li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">tuple</span></code></li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">dict</span></code></li>
|
||
</ul>
|
||
</section>
|
||
<section id="legal-optimizations">
|
||
<h3><a class="toc-backref" href="#legal-optimizations" role="doc-backlink">Legal optimizations</a></h3>
|
||
<p>The above semantics implies a lot of redundant effort and copying in the implementation.
|
||
However, it is possible to implement the above semantics efficiently by employing semantic preserving transformations
|
||
on the naive implementation.</p>
|
||
<p>When performing matching, implementations are allowed
|
||
to treat the following functions and methods as pure:</p>
|
||
<p>For any class supporting <code class="docutils literal notranslate"><span class="pre">MATCH_SEQUENCE</span></code>:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>* ``cls.__len__()``
|
||
* ``cls.__getitem__()``
|
||
</pre></div>
|
||
</div>
|
||
<p>For any class supporting <code class="docutils literal notranslate"><span class="pre">MATCH_MAPPING</span></code>:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>* ``cls.get()`` (Two argument form only)
|
||
</pre></div>
|
||
</div>
|
||
<p>Implementations are allowed to make the following assumptions:</p>
|
||
<ul class="simple">
|
||
<li><code class="docutils literal notranslate"><span class="pre">isinstance(obj,</span> <span class="pre">cls)</span></code> can be freely replaced with <code class="docutils literal notranslate"><span class="pre">issubclass(type(obj),</span> <span class="pre">cls)</span></code> and vice-versa.</li>
|
||
<li><code class="docutils literal notranslate"><span class="pre">isinstance(obj,</span> <span class="pre">cls)</span></code> will always return the same result for any <code class="docutils literal notranslate"><span class="pre">(obj,</span> <span class="pre">cls)</span></code> pair and repeated calls can thus be elided.</li>
|
||
<li>Reading any of <code class="docutils literal notranslate"><span class="pre">__match_container__</span></code>, <code class="docutils literal notranslate"><span class="pre">__match_class__</span></code> or <code class="docutils literal notranslate"><span class="pre">__match_args__</span></code> is a pure operation, and may be cached.</li>
|
||
<li>Sequences, that is any class for which <code class="docutils literal notranslate"><span class="pre">__match_container__</span> <span class="pre">==</span> <span class="pre">MATCH_SEQUENCE</span></code> is not zero, are not modified by iteration, subscripting or calls to <code class="docutils literal notranslate"><span class="pre">len()</span></code>.
|
||
Consequently, those operations can be freely substituted for each other where they would be equivalent when applied to an immutable sequence.</li>
|
||
<li>Mappings, that is any class for which <code class="docutils literal notranslate"><span class="pre">__match_container__</span> <span class="pre">==</span> <span class="pre">MATCH_MAPPING</span></code> is not zero, will not capture the second argument of the <code class="docutils literal notranslate"><span class="pre">get()</span></code> method.
|
||
So, the <code class="docutils literal notranslate"><span class="pre">$sentinel</span></code> value may be freely re-used.</li>
|
||
</ul>
|
||
<p>In fact, implementations are encouraged to make these assumptions, as it is likely to result in significantly better performance.</p>
|
||
</section>
|
||
</section>
|
||
<section id="security-implications">
|
||
<h2><a class="toc-backref" href="#security-implications" role="doc-backlink">Security Implications</a></h2>
|
||
<p>None.</p>
|
||
</section>
|
||
<section id="implementation">
|
||
<h2><a class="toc-backref" href="#implementation" role="doc-backlink">Implementation</a></h2>
|
||
<p>The naive implementation that follows from the specification will not be very efficient.
|
||
Fortunately, there are some reasonably straightforward transformations that can be used to improve performance.
|
||
Performance should be comparable to the implementation of <a class="pep reference internal" href="../pep-0634/" title="PEP 634 – Structural Pattern Matching: Specification">PEP 634</a> (at time of writing) by the release of 3.10.
|
||
Further performance improvements may have to wait for the 3.11 release.</p>
|
||
<section id="possible-optimizations">
|
||
<h3><a class="toc-backref" href="#possible-optimizations" role="doc-backlink">Possible optimizations</a></h3>
|
||
<p>The following is not part of the specification,
|
||
but guidelines to help developers create an efficient implementation.</p>
|
||
<section id="splitting-evaluation-into-lanes">
|
||
<h4><a class="toc-backref" href="#splitting-evaluation-into-lanes" role="doc-backlink">Splitting evaluation into lanes</a></h4>
|
||
<p>Since the first step in matching each pattern is check to against the kind, it is possible to combine all the checks against kind into a single multi-way branch at the beginning
|
||
of the match. The list of cases can then be duplicated into several “lanes” each corresponding to one kind.
|
||
It is then trivial to remove unmatchable cases from each lane.
|
||
Depending on the kind, different optimization strategies are possible for each lane.
|
||
Note that the body of the match clause does not need to be duplicated, just the pattern.</p>
|
||
</section>
|
||
<section id="id9">
|
||
<h4><a class="toc-backref" href="#id9" role="doc-backlink">Sequence patterns</a></h4>
|
||
<p>This is probably the most complex to optimize and the most profitable in terms of performance.
|
||
Since each pattern can only match a range of lengths, often only a single length,
|
||
the sequence of tests can be rewritten in as an explicit iteration over the sequence,
|
||
attempting to match only those patterns that apply to that sequence length.</p>
|
||
<p>For example:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">case</span> <span class="p">[]:</span>
|
||
<span class="n">A</span>
|
||
<span class="k">case</span> <span class="p">[</span><span class="n">x</span><span class="p">]:</span>
|
||
<span class="n">B</span>
|
||
<span class="k">case</span> <span class="p">[</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">]:</span>
|
||
<span class="n">C</span>
|
||
<span class="k">case</span> <span class="n">other</span><span class="p">:</span>
|
||
<span class="n">D</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Can be compiled roughly as:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> # Choose lane
|
||
$i = iter($value)
|
||
for $0 in $i:
|
||
break
|
||
else:
|
||
A
|
||
goto done
|
||
for $1 in $i:
|
||
break
|
||
else:
|
||
x = $0
|
||
B
|
||
goto done
|
||
for $2 in $i:
|
||
del $0, $1, $2
|
||
break
|
||
else:
|
||
x = $0
|
||
y = $1
|
||
C
|
||
goto done
|
||
other = $value
|
||
D
|
||
done:
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="id10">
|
||
<h4><a class="toc-backref" href="#id10" role="doc-backlink">Mapping patterns</a></h4>
|
||
<p>The best strategy here is probably to form a decision tree based on the size of the mapping and which keys are present.
|
||
There is no point repeatedly testing for the presence of a key.
|
||
For example:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">obj</span><span class="p">:</span>
|
||
<span class="k">case</span> <span class="p">{</span><span class="n">a</span><span class="p">:</span><span class="n">x</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span><span class="n">y</span><span class="p">}:</span>
|
||
<span class="n">W</span>
|
||
<span class="k">case</span> <span class="p">{</span><span class="n">a</span><span class="p">:</span><span class="n">x</span><span class="p">,</span> <span class="n">c</span><span class="p">:</span><span class="n">y</span><span class="p">}:</span>
|
||
<span class="n">X</span>
|
||
<span class="k">case</span><span class="w"> </span><span class="p">{</span><span class="n">a</span><span class="p">:</span><span class="n">x</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span><span class="k">_</span><span class="p">,</span> <span class="n">c</span><span class="p">:</span><span class="n">y</span><span class="p">}:</span>
|
||
<span class="n">Y</span>
|
||
<span class="k">case</span> <span class="n">other</span><span class="p">:</span>
|
||
<span class="n">Z</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>If the key <code class="docutils literal notranslate"><span class="pre">"a"</span></code> is not present when checking for case X, there is no need to check it again for Y.</p>
|
||
<p>The mapping lane can be implemented, roughly as:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span># Choose lane
|
||
if len($value) == 2:
|
||
if "a" in $value:
|
||
if "b" in $value:
|
||
x = $value["a"]
|
||
y = $value["b"]
|
||
goto W
|
||
if "c" in $value:
|
||
x = $value["a"]
|
||
y = $value["c"]
|
||
goto X
|
||
elif len($value) == 3:
|
||
if "a" in $value and "b" in $value:
|
||
x = $value["a"]
|
||
y = $value["c"]
|
||
goto Y
|
||
other = $value
|
||
goto Z
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
</section>
|
||
</section>
|
||
<section id="summary-of-differences-between-this-pep-and-pep-634">
|
||
<h2><a class="toc-backref" href="#summary-of-differences-between-this-pep-and-pep-634" role="doc-backlink">Summary of differences between this PEP and PEP 634</a></h2>
|
||
<p>The changes to the semantics can be summarized as:</p>
|
||
<ul class="simple">
|
||
<li>Requires <code class="docutils literal notranslate"><span class="pre">__match_args__</span></code> to be a <em>tuple</em> of strings, not just a sequence.
|
||
This make pattern matching a bit more robust and optimizable as <code class="docutils literal notranslate"><span class="pre">__match_args__</span></code> can be assumed to be immutable.</li>
|
||
<li>Selecting the kind of container patterns that can be matched uses <code class="docutils literal notranslate"><span class="pre">cls.__match_container__</span></code> instead of
|
||
<code class="docutils literal notranslate"><span class="pre">issubclass(cls,</span> <span class="pre">collections.abc.Mapping)</span></code> and <code class="docutils literal notranslate"><span class="pre">issubclass(cls,</span> <span class="pre">collections.abc.Sequence)</span></code>.</li>
|
||
<li>Allows classes to opt out of deconstruction altogether, if necessary, but setting <code class="docutils literal notranslate"><span class="pre">__match_class__</span> <span class="pre">=</span> <span class="pre">0</span></code>.</li>
|
||
<li>The behavior when matching patterns is more precisely defined, but is otherwise unchanged.</li>
|
||
</ul>
|
||
<p>There are no changes to syntax. All examples given in the <a class="pep reference internal" href="../pep-0636/" title="PEP 636 – Structural Pattern Matching: Tutorial">PEP 636</a> tutorial should continue to work as they do now.</p>
|
||
</section>
|
||
<section id="rejected-ideas">
|
||
<h2><a class="toc-backref" href="#rejected-ideas" role="doc-backlink">Rejected Ideas</a></h2>
|
||
<section id="using-attributes-from-the-instance-s-dictionary">
|
||
<h3><a class="toc-backref" href="#using-attributes-from-the-instance-s-dictionary" role="doc-backlink">Using attributes from the instance’s dictionary</a></h3>
|
||
<p>An earlier version of this PEP only used attributes from the instance’s dictionary when matching a class pattern with <code class="docutils literal notranslate"><span class="pre">__match_class__</span></code> was the default value.
|
||
The intent was to avoid capturing bound-methods and other synthetic attributes. However, this also mean that properties were ignored.</p>
|
||
<p>For the class:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">C</span><span class="p">:</span>
|
||
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">a</span> <span class="o">=</span> <span class="s2">"a"</span>
|
||
<span class="nd">@property</span>
|
||
<span class="k">def</span> <span class="nf">p</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="o">...</span>
|
||
<span class="k">def</span> <span class="nf">m</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Ideally we would match the attributes “a” and “p”, but not “m”.
|
||
However, there is no general way to do that, so this PEP now follows the semantics of <a class="pep reference internal" href="../pep-0634/" title="PEP 634 – Structural Pattern Matching: Specification">PEP 634</a>.</p>
|
||
</section>
|
||
<section id="lookup-of-match-args-on-the-subject-not-the-pattern">
|
||
<h3><a class="toc-backref" href="#lookup-of-match-args-on-the-subject-not-the-pattern" role="doc-backlink">Lookup of <code class="docutils literal notranslate"><span class="pre">__match_args__</span></code> on the subject not the pattern</a></h3>
|
||
<p>An earlier version of this PEP looked up <code class="docutils literal notranslate"><span class="pre">__match_args__</span></code> on the class of the subject and
|
||
not the class specified in the pattern.
|
||
This has been rejected for a few reasons:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">*</span> <span class="n">Using</span> <span class="n">the</span> <span class="k">class</span> <span class="nc">specified</span> <span class="ow">in</span> <span class="n">the</span> <span class="n">pattern</span> <span class="ow">is</span> <span class="n">more</span> <span class="n">amenable</span> <span class="n">to</span> <span class="n">optimization</span> <span class="ow">and</span> <span class="n">can</span> <span class="n">offer</span> <span class="n">better</span> <span class="n">performance</span><span class="o">.</span>
|
||
<span class="o">*</span> <span class="n">Using</span> <span class="n">the</span> <span class="k">class</span> <span class="nc">specified</span> <span class="ow">in</span> <span class="n">the</span> <span class="n">pattern</span> <span class="n">has</span> <span class="n">the</span> <span class="n">potential</span> <span class="n">to</span> <span class="n">provide</span> <span class="n">better</span> <span class="n">error</span> <span class="n">reporting</span> <span class="ow">is</span> <span class="n">some</span> <span class="n">cases</span><span class="o">.</span>
|
||
<span class="o">*</span> <span class="n">Neither</span> <span class="n">approach</span> <span class="ow">is</span> <span class="n">perfect</span><span class="p">,</span> <span class="n">both</span> <span class="n">have</span> <span class="n">odd</span> <span class="n">corner</span> <span class="n">cases</span><span class="o">.</span> <span class="n">Keeping</span> <span class="n">the</span> <span class="n">status</span> <span class="n">quo</span> <span class="n">minimizes</span> <span class="n">disruption</span><span class="o">.</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="combining-match-class-and-match-container-into-a-single-value">
|
||
<h3><a class="toc-backref" href="#combining-match-class-and-match-container-into-a-single-value" role="doc-backlink">Combining <code class="docutils literal notranslate"><span class="pre">__match_class__</span></code> and <code class="docutils literal notranslate"><span class="pre">__match_container__</span></code> into a single value</a></h3>
|
||
<p>An earlier version of this PEP combined <code class="docutils literal notranslate"><span class="pre">__match_class__</span></code> and <code class="docutils literal notranslate"><span class="pre">__match_container__</span></code> into a single value, <code class="docutils literal notranslate"><span class="pre">__match_kind__</span></code>.
|
||
Using a single value has a small advantage in terms of performance,
|
||
but is likely to result in unintended changes to container matching when overriding class matching behavior, and vice versa.</p>
|
||
</section>
|
||
</section>
|
||
<section id="deferred-ideas">
|
||
<h2><a class="toc-backref" href="#deferred-ideas" role="doc-backlink">Deferred Ideas</a></h2>
|
||
<p>The original version of this PEP included the match kind <code class="docutils literal notranslate"><span class="pre">MATCH_POSITIONAL</span></code> and special method
|
||
<code class="docutils literal notranslate"><span class="pre">__deconstruct__</span></code> which would allow classes full control over their matching. This is important
|
||
for libraries like <code class="docutils literal notranslate"><span class="pre">sympy</span></code>.</p>
|
||
<p>For example, using <code class="docutils literal notranslate"><span class="pre">sympy</span></code>, we might want to write:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># sin(x)**2 + cos(x)**2 == 1</span>
|
||
<span class="k">case</span> <span class="n">Add</span><span class="p">(</span><span class="n">Pow</span><span class="p">(</span><span class="n">sin</span><span class="p">(</span><span class="n">a</span><span class="p">),</span> <span class="mi">2</span><span class="p">),</span> <span class="n">Pow</span><span class="p">(</span><span class="n">cos</span><span class="p">(</span><span class="n">b</span><span class="p">),</span> <span class="mi">2</span><span class="p">))</span> <span class="k">if</span> <span class="n">a</span> <span class="o">==</span> <span class="n">b</span><span class="p">:</span>
|
||
<span class="k">return</span> <span class="mi">1</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>For <code class="docutils literal notranslate"><span class="pre">sympy</span></code> to support the positional patterns with current pattern matching is possible,
|
||
but is tricky. With these additional features it can be implemented easily <a class="footnote-reference brackets" href="#id20" id="id11">[9]</a>.</p>
|
||
<p>This idea will feature in a future PEP for 3.11.
|
||
However, it is too late in the 3.10 development cycle for such a change.</p>
|
||
<section id="having-a-separate-value-to-reject-all-class-matches">
|
||
<h3><a class="toc-backref" href="#having-a-separate-value-to-reject-all-class-matches" role="doc-backlink">Having a separate value to reject all class matches</a></h3>
|
||
<p>In an earlier version of this PEP, there was a distinct value for <code class="docutils literal notranslate"><span class="pre">__match_class__</span></code> that allowed classes to not match any class
|
||
pattern that would have required deconstruction. However, this would become redundant once <code class="docutils literal notranslate"><span class="pre">MATCH_POSITIONAL</span></code> is introduced, and
|
||
complicates the specification for an extremely rare case.</p>
|
||
</section>
|
||
</section>
|
||
<section id="code-examples">
|
||
<h2><a class="toc-backref" href="#code-examples" role="doc-backlink">Code examples</a></h2>
|
||
<aside class="footnote-list brackets">
|
||
<aside class="footnote brackets" id="id12" role="doc-footnote">
|
||
<dt class="label" id="id12">[<a href="#id1">1</a>]</dt>
|
||
<dd></aside>
|
||
</aside>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Symbol</span><span class="p">:</span>
|
||
<span class="n">__match_class__</span> <span class="o">=</span> <span class="n">MATCH_SELF</span>
|
||
</pre></div>
|
||
</div>
|
||
<aside class="footnote-list brackets">
|
||
<aside class="footnote brackets" id="id13" role="doc-footnote">
|
||
<dt class="label" id="id13">[<a href="#id2">2</a>]</dt>
|
||
<dd></aside>
|
||
</aside>
|
||
<p>This:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">case</span> <span class="p">[</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">]</span> <span class="k">if</span> <span class="n">a</span> <span class="ow">is</span> <span class="n">b</span><span class="p">:</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>translates to:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>$kind = type($value).__match_container__
|
||
if $kind != MATCH_SEQUENCE:
|
||
FAIL
|
||
if len($value) != 2:
|
||
FAIL
|
||
a, b = $value
|
||
if not a is b:
|
||
FAIL
|
||
</pre></div>
|
||
</div>
|
||
<aside class="footnote-list brackets">
|
||
<aside class="footnote brackets" id="id14" role="doc-footnote">
|
||
<dt class="label" id="id14">[<a href="#id3">3</a>]</dt>
|
||
<dd></aside>
|
||
</aside>
|
||
<p>This:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">case</span> <span class="p">[</span><span class="n">a</span><span class="p">,</span> <span class="o">*</span><span class="n">b</span><span class="p">,</span> <span class="n">c</span><span class="p">]:</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>translates to:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>$kind = type($value).__match_container__
|
||
if $kind != MATCH_SEQUENCE:
|
||
FAIL
|
||
if len($value) < 2:
|
||
FAIL
|
||
a, *b, c = $value
|
||
</pre></div>
|
||
</div>
|
||
<aside class="footnote-list brackets">
|
||
<aside class="footnote brackets" id="id15" role="doc-footnote">
|
||
<dt class="label" id="id15">[<a href="#id4">4</a>]</dt>
|
||
<dd></aside>
|
||
</aside>
|
||
<p>This:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">case</span> <span class="p">{</span><span class="s2">"x"</span><span class="p">:</span> <span class="n">x</span><span class="p">,</span> <span class="s2">"y"</span><span class="p">:</span> <span class="n">y</span><span class="p">}</span> <span class="k">if</span> <span class="n">x</span> <span class="o">></span> <span class="mi">2</span><span class="p">:</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>translates to:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>$kind = type($value).__match_container__
|
||
if $kind != MATCH_MAPPING:
|
||
FAIL
|
||
$tmp = $value.get("x", $sentinel)
|
||
if $tmp is $sentinel:
|
||
FAIL
|
||
x = $tmp
|
||
$tmp = $value.get("y", $sentinel)
|
||
if $tmp is $sentinel:
|
||
FAIL
|
||
y = $tmp
|
||
if not x > 2:
|
||
FAIL
|
||
</pre></div>
|
||
</div>
|
||
<aside class="footnote-list brackets">
|
||
<aside class="footnote brackets" id="id16" role="doc-footnote">
|
||
<dt class="label" id="id16">[<a href="#id5">5</a>]</dt>
|
||
<dd></aside>
|
||
</aside>
|
||
<p>This:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">case</span> <span class="p">{</span><span class="s2">"x"</span><span class="p">:</span> <span class="n">x</span><span class="p">,</span> <span class="s2">"y"</span><span class="p">:</span> <span class="n">y</span><span class="p">,</span> <span class="o">**</span><span class="n">z</span><span class="p">}:</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>translates to:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>$kind = type($value).__match_container__
|
||
if $kind != MATCH_MAPPING:
|
||
FAIL
|
||
$tmp = dict($value)
|
||
if not $tmp.keys() >= {"x", "y"}:
|
||
FAIL
|
||
x = $tmp.pop("x")
|
||
y = $tmp.pop("y")
|
||
z = $tmp
|
||
</pre></div>
|
||
</div>
|
||
<aside class="footnote-list brackets">
|
||
<aside class="footnote brackets" id="id17" role="doc-footnote">
|
||
<dt class="label" id="id17">[<a href="#id6">6</a>]</dt>
|
||
<dd></aside>
|
||
</aside>
|
||
<p>This:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">ClsName</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">):</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>translates to:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>if not isinstance($value, ClsName):
|
||
FAIL
|
||
$attrs = ClsName.__match_args__
|
||
if len($attr) < 2:
|
||
FAIL
|
||
try:
|
||
x = getattr($value, $attrs[0])
|
||
y = getattr($value, $attrs[1])
|
||
except AttributeError:
|
||
FAIL
|
||
</pre></div>
|
||
</div>
|
||
<aside class="footnote-list brackets">
|
||
<aside class="footnote brackets" id="id18" role="doc-footnote">
|
||
<dt class="label" id="id18">[<a href="#id7">7</a>]</dt>
|
||
<dd></aside>
|
||
</aside>
|
||
<p>This:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">ClsName</span><span class="p">(</span><span class="n">a</span><span class="o">=</span><span class="n">x</span><span class="p">,</span> <span class="n">b</span><span class="o">=</span><span class="n">y</span><span class="p">):</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>translates to:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>if not isinstance($value, ClsName):
|
||
FAIL
|
||
try:
|
||
x = $value.a
|
||
y = $value.b
|
||
except AttributeError:
|
||
FAIL
|
||
</pre></div>
|
||
</div>
|
||
<aside class="footnote-list brackets">
|
||
<aside class="footnote brackets" id="id19" role="doc-footnote">
|
||
<dt class="label" id="id19">[<a href="#id8">8</a>]</dt>
|
||
<dd></aside>
|
||
</aside>
|
||
<p>This:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">ClsName</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">a</span><span class="o">=</span><span class="n">y</span><span class="p">):</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>translates to:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>if not isinstance($value, ClsName):
|
||
FAIL
|
||
$attrs = ClsName.__match_args__
|
||
if len($attr) < 1:
|
||
raise TypeError(...)
|
||
$positional_names = $attrs[:1]
|
||
try:
|
||
x = getattr($value, $attrs[0])
|
||
if "a" in $positional_names:
|
||
raise TypeError(...)
|
||
y = $value.a
|
||
except AttributeError:
|
||
FAIL
|
||
</pre></div>
|
||
</div>
|
||
<aside class="footnote-list brackets">
|
||
<aside class="footnote brackets" id="id20" role="doc-footnote">
|
||
<dt class="label" id="id20">[<a href="#id11">9</a>]</dt>
|
||
<dd></aside>
|
||
</aside>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Basic</span><span class="p">:</span>
|
||
<span class="n">__match_class__</span> <span class="o">=</span> <span class="n">MATCH_POSITIONAL</span>
|
||
<span class="k">def</span> <span class="nf">__deconstruct__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_args</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="copyright">
|
||
<h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2>
|
||
<p>This document is placed in the public domain or under the
|
||
CC0-1.0-Universal license, whichever is more permissive.</p>
|
||
</section>
|
||
</section>
|
||
<hr class="docutils" />
|
||
<p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0653.rst">https://github.com/python/peps/blob/main/peps/pep-0653.rst</a></p>
|
||
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0653.rst">2023-09-09 17:39:29 GMT</a></p>
|
||
|
||
</article>
|
||
<nav id="pep-sidebar">
|
||
<h2>Contents</h2>
|
||
<ul>
|
||
<li><a class="reference internal" href="#abstract">Abstract</a></li>
|
||
<li><a class="reference internal" href="#motivation">Motivation</a><ul>
|
||
<li><a class="reference internal" href="#precise-semantics">Precise semantics</a></li>
|
||
<li><a class="reference internal" href="#improved-control-over-class-matching">Improved control over class matching</a></li>
|
||
<li><a class="reference internal" href="#robustness">Robustness</a></li>
|
||
<li><a class="reference internal" href="#efficient-implementation">Efficient implementation</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#rationale">Rationale</a></li>
|
||
<li><a class="reference internal" href="#specification">Specification</a><ul>
|
||
<li><a class="reference internal" href="#additions-to-the-object-model">Additions to the object model</a></li>
|
||
<li><a class="reference internal" href="#semantics-of-the-matching-process">Semantics of the matching process</a><ul>
|
||
<li><a class="reference internal" href="#preamble">Preamble</a></li>
|
||
<li><a class="reference internal" href="#capture-patterns">Capture patterns</a></li>
|
||
<li><a class="reference internal" href="#wildcard-patterns">Wildcard patterns</a></li>
|
||
<li><a class="reference internal" href="#literal-patterns">Literal Patterns</a></li>
|
||
<li><a class="reference internal" href="#value-patterns">Value Patterns</a></li>
|
||
<li><a class="reference internal" href="#sequence-patterns">Sequence Patterns</a></li>
|
||
<li><a class="reference internal" href="#mapping-patterns">Mapping Patterns</a></li>
|
||
<li><a class="reference internal" href="#class-patterns">Class Patterns</a></li>
|
||
<li><a class="reference internal" href="#nested-patterns">Nested patterns</a></li>
|
||
<li><a class="reference internal" href="#guards">Guards</a></li>
|
||
<li><a class="reference internal" href="#non-conforming-special-attributes">Non-conforming special attributes</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#values-of-the-special-attributes-for-classes-in-the-standard-library">Values of the special attributes for classes in the standard library</a></li>
|
||
<li><a class="reference internal" href="#legal-optimizations">Legal optimizations</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#security-implications">Security Implications</a></li>
|
||
<li><a class="reference internal" href="#implementation">Implementation</a><ul>
|
||
<li><a class="reference internal" href="#possible-optimizations">Possible optimizations</a><ul>
|
||
<li><a class="reference internal" href="#splitting-evaluation-into-lanes">Splitting evaluation into lanes</a></li>
|
||
<li><a class="reference internal" href="#id9">Sequence patterns</a></li>
|
||
<li><a class="reference internal" href="#id10">Mapping patterns</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#summary-of-differences-between-this-pep-and-pep-634">Summary of differences between this PEP and PEP 634</a></li>
|
||
<li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul>
|
||
<li><a class="reference internal" href="#using-attributes-from-the-instance-s-dictionary">Using attributes from the instance’s dictionary</a></li>
|
||
<li><a class="reference internal" href="#lookup-of-match-args-on-the-subject-not-the-pattern">Lookup of <code class="docutils literal notranslate"><span class="pre">__match_args__</span></code> on the subject not the pattern</a></li>
|
||
<li><a class="reference internal" href="#combining-match-class-and-match-container-into-a-single-value">Combining <code class="docutils literal notranslate"><span class="pre">__match_class__</span></code> and <code class="docutils literal notranslate"><span class="pre">__match_container__</span></code> into a single value</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#deferred-ideas">Deferred Ideas</a><ul>
|
||
<li><a class="reference internal" href="#having-a-separate-value-to-reject-all-class-matches">Having a separate value to reject all class matches</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#code-examples">Code examples</a></li>
|
||
<li><a class="reference internal" href="#copyright">Copyright</a></li>
|
||
</ul>
|
||
|
||
<br>
|
||
<a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0653.rst">Page Source (GitHub)</a>
|
||
</nav>
|
||
</section>
|
||
<script src="../_static/colour_scheme.js"></script>
|
||
<script src="../_static/wrap_tables.js"></script>
|
||
<script src="../_static/sticky_banner.js"></script>
|
||
</body>
|
||
</html> |