python-peps/pep-0622/index.html

2329 lines
208 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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 622 Structural Pattern Matching | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-0622/">
<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 622 Structural Pattern Matching | peps.python.org'>
<meta property="og:description" content="This PEP proposes to add a pattern matching statement to Python, inspired by similar syntax found in Scala, Erlang, and other languages.">
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-0622/">
<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="This PEP proposes to add a pattern matching statement to Python, inspired by similar syntax found in Scala, Erlang, and other languages.">
<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> &raquo; </li>
<li><a href="../pep-0000/">PEP Index</a> &raquo; </li>
<li>PEP 622</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 622 Structural Pattern Matching</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Brandt Bucher &lt;brandt&#32;&#97;t&#32;python.org&gt;,
Daniel F Moisset &lt;dfmoisset&#32;&#97;t&#32;gmail.com&gt;,
Tobias Kohn &lt;kohnt&#32;&#97;t&#32;tobiaskohn.ch&gt;,
Ivan Levkivskyi &lt;levkivskyi&#32;&#97;t&#32;gmail.com&gt;,
Guido van Rossum &lt;guido&#32;&#97;t&#32;python.org&gt;,
Talin &lt;viridia&#32;&#97;t&#32;gmail.com&gt;</dd>
<dt class="field-even">BDFL-Delegate<span class="colon">:</span></dt>
<dd class="field-even"><p></p></dd>
<dt class="field-odd">Discussions-To<span class="colon">:</span></dt>
<dd class="field-odd"><a class="reference external" href="https://mail.python.org/archives/list/python-dev&#64;python.org/">Python-Dev list</a></dd>
<dt class="field-even">Status<span class="colon">:</span></dt>
<dd class="field-even"><abbr title="Replaced by another succeeding PEP">Superseded</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">23-Jun-2020</dd>
<dt class="field-odd">Python-Version<span class="colon">:</span></dt>
<dd class="field-odd">3.10</dd>
<dt class="field-even">Post-History<span class="colon">:</span></dt>
<dd class="field-even">23-Jun-2020, 08-Jul-2020</dd>
<dt class="field-odd">Superseded-By<span class="colon">:</span></dt>
<dd class="field-odd"><a class="reference external" href="../pep-0634/">634</a></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><ul>
<li><a class="reference internal" href="#patterns-and-shapes">Patterns and shapes</a></li>
<li><a class="reference internal" href="#syntax">Syntax</a></li>
<li><a class="reference internal" href="#motivation">Motivation</a></li>
</ul>
</li>
<li><a class="reference internal" href="#overview">Overview</a><ul>
<li><a class="reference internal" href="#pattern-a-new-syntactic-construct-and-destructuring">Pattern, a new syntactic construct, and destructuring</a></li>
<li><a class="reference internal" href="#matching-process">Matching process</a></li>
</ul>
</li>
<li><a class="reference internal" href="#rationale-and-goals">Rationale and Goals</a></li>
<li><a class="reference internal" href="#syntax-and-semantics">Syntax and Semantics</a><ul>
<li><a class="reference internal" href="#patterns">Patterns</a></li>
<li><a class="reference internal" href="#the-match-statement">The <code class="docutils literal notranslate"><span class="pre">match</span></code> statement</a></li>
<li><a class="reference internal" href="#match-semantics">Match semantics</a></li>
<li><a class="reference internal" href="#allowed-patterns">Allowed patterns</a><ul>
<li><a class="reference internal" href="#literal-patterns">Literal Patterns</a></li>
<li><a class="reference internal" href="#capture-patterns">Capture Patterns</a></li>
<li><a class="reference internal" href="#wildcard-pattern">Wildcard Pattern</a></li>
<li><a class="reference internal" href="#constant-value-patterns">Constant 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>
</ul>
</li>
<li><a class="reference internal" href="#combining-multiple-patterns-or-patterns">Combining multiple patterns (OR patterns)</a></li>
<li><a class="reference internal" href="#guards">Guards</a></li>
<li><a class="reference internal" href="#walrus-patterns">Walrus patterns</a></li>
</ul>
</li>
<li><a class="reference internal" href="#runtime-specification">Runtime specification</a><ul>
<li><a class="reference internal" href="#the-match-protocol">The Match Protocol</a></li>
<li><a class="reference internal" href="#overlapping-sub-patterns">Overlapping sub-patterns</a></li>
<li><a class="reference internal" href="#special-attribute-match-args">Special attribute <code class="docutils literal notranslate"><span class="pre">__match_args__</span></code></a></li>
<li><a class="reference internal" href="#exceptions-and-side-effects">Exceptions and side effects</a></li>
<li><a class="reference internal" href="#the-standard-library">The standard library</a></li>
</ul>
</li>
<li><a class="reference internal" href="#static-checkers-specification">Static checkers specification</a><ul>
<li><a class="reference internal" href="#exhaustiveness-checks">Exhaustiveness checks</a></li>
<li><a class="reference internal" href="#sealed-classes-as-algebraic-data-types">Sealed classes as algebraic data types</a></li>
<li><a class="reference internal" href="#type-erasure">Type erasure</a></li>
<li><a class="reference internal" href="#note-about-constants">Note about constants</a></li>
<li><a class="reference internal" href="#precise-type-checking-of-star-matches">Precise type checking of star matches</a></li>
</ul>
</li>
<li><a class="reference internal" href="#performance-considerations">Performance Considerations</a></li>
<li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a></li>
<li><a class="reference internal" href="#impacts-on-third-party-tools">Impacts on third-party tools</a></li>
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li>
<li><a class="reference internal" href="#example-code">Example Code</a></li>
<li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul>
<li><a class="reference internal" href="#don-t-do-this-pattern-matching-is-hard-to-learn">Dont do this, pattern matching is hard to learn</a></li>
<li><a class="reference internal" href="#don-t-do-this-use-existing-method-dispatching-mechanisms">Dont do this, use existing method dispatching mechanisms</a></li>
<li><a class="reference internal" href="#allow-more-flexible-assignment-targets-instead">Allow more flexible assignment targets instead</a></li>
<li><a class="reference internal" href="#make-it-an-expression">Make it an expression</a></li>
<li><a class="reference internal" href="#use-a-hard-keyword">Use a hard keyword</a></li>
<li><a class="reference internal" href="#use-as-or-instead-of-case-for-case-clauses">Use <code class="docutils literal notranslate"><span class="pre">as</span></code> or <code class="docutils literal notranslate"><span class="pre">|</span></code> instead of <code class="docutils literal notranslate"><span class="pre">case</span></code> for case clauses</a></li>
<li><a class="reference internal" href="#use-a-flat-indentation-scheme">Use a flat indentation scheme</a></li>
<li><a class="reference internal" href="#alternatives-for-constant-value-pattern">Alternatives for constant value pattern</a></li>
<li><a class="reference internal" href="#disallow-float-literals-in-patterns">Disallow float literals in patterns</a></li>
<li><a class="reference internal" href="#range-matching-patterns">Range matching patterns</a></li>
<li><a class="reference internal" href="#use-dispatch-dict-semantics-for-matches">Use dispatch dict semantics for matches</a></li>
<li><a class="reference internal" href="#use-continue-and-break-in-case-clauses">Use <code class="docutils literal notranslate"><span class="pre">continue</span></code> and <code class="docutils literal notranslate"><span class="pre">break</span></code> in case clauses.</a></li>
<li><a class="reference internal" href="#and-patterns">AND (<code class="docutils literal notranslate"><span class="pre">&amp;</span></code>) patterns</a></li>
<li><a class="reference internal" href="#negative-match-patterns">Negative match patterns</a></li>
<li><a class="reference internal" href="#check-exhaustiveness-at-runtime">Check exhaustiveness at runtime</a></li>
<li><a class="reference internal" href="#type-annotations-for-pattern-variables">Type annotations for pattern variables</a></li>
<li><a class="reference internal" href="#allow-rest-in-class-patterns">Allow <code class="docutils literal notranslate"><span class="pre">*rest</span></code> in class patterns</a></li>
<li><a class="reference internal" href="#disallow-a-in-constant-value-patterns">Disallow <code class="docutils literal notranslate"><span class="pre">_.a</span></code> in constant value patterns</a></li>
<li><a class="reference internal" href="#use-some-other-token-as-wildcard">Use some other token as wildcard</a></li>
<li><a class="reference internal" href="#use-some-other-syntax-instead-of-for-or-patterns">Use some other syntax instead of <code class="docutils literal notranslate"><span class="pre">|</span></code> for OR patterns</a></li>
<li><a class="reference internal" href="#add-an-else-clause">Add an <code class="docutils literal notranslate"><span class="pre">else</span></code> clause</a></li>
</ul>
</li>
<li><a class="reference internal" href="#deferred-ideas">Deferred Ideas</a><ul>
<li><a class="reference internal" href="#one-off-syntax-variant">One-off syntax variant</a></li>
<li><a class="reference internal" href="#other-pattern-based-constructions">Other pattern-based constructions</a></li>
<li><a class="reference internal" href="#algebraic-matching-of-repeated-names">Algebraic matching of repeated names</a></li>
<li><a class="reference internal" href="#custom-matching-protocol">Custom matching protocol</a></li>
<li><a class="reference internal" href="#parameterized-matching-syntax">Parameterized Matching Syntax</a></li>
<li><a class="reference internal" href="#pattern-utility-library">Pattern Utility Library</a></li>
</ul>
</li>
<li><a class="reference internal" href="#acknowledgments">Acknowledgments</a></li>
<li><a class="reference internal" href="#version-history">Version History</a></li>
<li><a class="reference internal" href="#references">References</a></li>
<li><a class="reference internal" href="#appendix-a-full-grammar">Appendix A Full Grammar</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 to add a <strong>pattern matching statement</strong> to Python,
inspired by similar syntax found in Scala, Erlang, and other languages.</p>
<section id="patterns-and-shapes">
<h3><a class="toc-backref" href="#patterns-and-shapes" role="doc-backlink">Patterns and shapes</a></h3>
<p>The <strong>pattern syntax</strong> builds on Pythons existing syntax for sequence
unpacking (e.g., <code class="docutils literal notranslate"><span class="pre">a,</span> <span class="pre">b</span> <span class="pre">=</span> <span class="pre">value</span></code>).</p>
<p>A <code class="docutils literal notranslate"><span class="pre">match</span></code> statement compares a value (the <strong>subject</strong>)
to several different shapes (the <strong>patterns</strong>) until a shape fits.
Each pattern describes the type and structure of the accepted values
as well as the variables where to capture its contents.</p>
<p>Patterns can specify the shape to be:</p>
<ul class="simple">
<li>a sequence to be unpacked, as already mentioned</li>
<li>a mapping with specific keys</li>
<li>an instance of a given class with (optionally) specific attributes</li>
<li>a specific value</li>
<li>a wildcard</li>
</ul>
<p>Patterns can be composed in several ways.</p>
</section>
<section id="syntax">
<h3><a class="toc-backref" href="#syntax" role="doc-backlink">Syntax</a></h3>
<p>Syntactically, a <code class="docutils literal notranslate"><span class="pre">match</span></code> statement contains:</p>
<ul class="simple">
<li>a <em>subject</em> expression</li>
<li>one or more <code class="docutils literal notranslate"><span class="pre">case</span></code> clauses</li>
</ul>
<p>Each <code class="docutils literal notranslate"><span class="pre">case</span></code> clause specifies:</p>
<ul class="simple">
<li>a pattern (the overall shape to be matched)</li>
<li>an optional “guard” (a condition to be checked if the pattern matches)</li>
<li>a code block to be executed if the case clause is selected</li>
</ul>
</section>
<section id="motivation">
<h3><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h3>
<p>The rest of the PEP:</p>
<ul class="simple">
<li>motivates why we believe pattern matching makes a good addition to Python</li>
<li>explains our design choices</li>
<li>contains a precise syntactic and runtime specification</li>
<li>gives guidance for static type checkers (and one small addition to the <code class="docutils literal notranslate"><span class="pre">typing</span></code> module)</li>
<li>discusses the main objections and alternatives that have been
brought up during extensive discussion of the proposal, both within
the group of authors and in the python-dev community</li>
</ul>
<p>Finally, we discuss some possible extensions that might be considered
in the future, once the community has ample experience with the
currently proposed syntax and semantics.</p>
</section>
</section>
<section id="overview">
<h2><a class="toc-backref" href="#overview" role="doc-backlink">Overview</a></h2>
<p>Patterns are a new syntactical category with their own rules
and special cases. Patterns mix input (given values) and output
(captured variables) in novel ways. They may take a little time to
use effectively. The authors have provided
a brief introduction to the basic concepts here. Note that this section
is not intended to be complete or entirely accurate.</p>
<section id="pattern-a-new-syntactic-construct-and-destructuring">
<h3><a class="toc-backref" href="#pattern-a-new-syntactic-construct-and-destructuring" role="doc-backlink">Pattern, a new syntactic construct, and destructuring</a></h3>
<p>A new syntactic construct called <strong>pattern</strong> is introduced in this
PEP. Syntactically, patterns look like a subset of expressions.
The following are examples of patterns:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">[first,</span> <span class="pre">second,</span> <span class="pre">*rest]</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">Point2d(x,</span> <span class="pre">0)</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">{&quot;name&quot;:</span> <span class="pre">&quot;Bruce&quot;,</span> <span class="pre">&quot;age&quot;:</span> <span class="pre">age}</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">42</span></code></li>
</ul>
<p>The above expressions may look like examples of object construction
with a constructor which takes some values as parameters and
builds an object from those components.</p>
<p>When viewed as a pattern, the above patterns mean the inverse operation of
construction, which we call <strong>destructuring</strong>. <strong>Destructuring</strong> takes a subject value
and extracts its components.</p>
<p>The syntactic similarity between object construction and destructuring is
intentional. It also follows the existing
Pythonic style of contexts which makes assignment targets (write contexts) look
like expressions (read contexts).</p>
<p>Pattern matching never creates objects. This is in the same way that
<code class="docutils literal notranslate"><span class="pre">[a,</span> <span class="pre">b]</span> <span class="pre">=</span> <span class="pre">my_list</span></code> doesnt create a
new <code class="docutils literal notranslate"><span class="pre">[a,</span> <span class="pre">b]</span></code> list, nor reads the values of <code class="docutils literal notranslate"><span class="pre">a</span></code> and <code class="docutils literal notranslate"><span class="pre">b</span></code>.</p>
</section>
<section id="matching-process">
<h3><a class="toc-backref" href="#matching-process" role="doc-backlink">Matching process</a></h3>
<p>During this matching process,
the structure of the pattern may not fit the subject, and matching <em>fails</em>.</p>
<p>For example, matching the pattern <code class="docutils literal notranslate"><span class="pre">Point2d(x,</span> <span class="pre">0)</span></code> to the subject
<code class="docutils literal notranslate"><span class="pre">Point2d(3,</span> <span class="pre">0)</span></code> successfully matches. The match also <strong>binds</strong>
the patterns free variable <code class="docutils literal notranslate"><span class="pre">x</span></code> to the subjects value <code class="docutils literal notranslate"><span class="pre">3</span></code>.</p>
<p>As another example, if the subject is <code class="docutils literal notranslate"><span class="pre">[3,</span> <span class="pre">0]</span></code>, the match fails
because the subjects type <code class="docutils literal notranslate"><span class="pre">list</span></code> is not the patterns <code class="docutils literal notranslate"><span class="pre">Point2d</span></code>.</p>
<p>As a third example, if the subject is
<code class="docutils literal notranslate"><span class="pre">Point2d(3,</span> <span class="pre">7)</span></code>, the match fails because the
subjects second coordinate <code class="docutils literal notranslate"><span class="pre">7</span></code> is not the same as the patterns <code class="docutils literal notranslate"><span class="pre">0</span></code>.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">match</span></code> statement tries to match a single subject to each of the
patterns in its <code class="docutils literal notranslate"><span class="pre">case</span></code> clauses. At the first
successful match to a pattern in a <code class="docutils literal notranslate"><span class="pre">case</span></code> clause:</p>
<ul class="simple">
<li>the variables in the pattern are assigned, and</li>
<li>a corresponding block is executed.</li>
</ul>
<p>Each <code class="docutils literal notranslate"><span class="pre">case</span></code> clause can also specify an optional boolean condition,
known as a <strong>guard</strong>.</p>
<p>Lets look at a more detailed example of a <code class="docutils literal notranslate"><span class="pre">match</span></code> statement. The
<code class="docutils literal notranslate"><span class="pre">match</span></code> statement is used within a function to define the building
of 3D points. In this example, the function can accept as input any of
the following: tuple with 2 elements, tuple with 3 elements, an
existing Point2d object or an existing Point3d object:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">make_point_3d</span><span class="p">(</span><span class="n">pt</span><span class="p">):</span>
<span class="k">match</span> <span class="n">pt</span><span class="p">:</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="k">return</span> <span class="n">Point3d</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="mi">0</span><span class="p">)</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">z</span><span class="p">):</span>
<span class="k">return</span> <span class="n">Point3d</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">z</span><span class="p">)</span>
<span class="k">case</span> <span class="n">Point2d</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="k">return</span> <span class="n">Point3d</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="mi">0</span><span class="p">)</span>
<span class="k">case</span><span class="w"> </span><span class="n">Point3d</span><span class="p">(</span><span class="k">_</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span><span class="p">):</span>
<span class="k">return</span> <span class="n">pt</span>
<span class="k">case</span><span class="w"> </span><span class="k">_</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="s2">&quot;not a point we support&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>Without pattern matching, this functions implementation would require several
<code class="docutils literal notranslate"><span class="pre">isinstance()</span></code> checks, one or two <code class="docutils literal notranslate"><span class="pre">len()</span></code> calls, and a more
convoluted control flow. The <code class="docutils literal notranslate"><span class="pre">match</span></code> example version and the traditional
Python version without <code class="docutils literal notranslate"><span class="pre">match</span></code> translate into similar code under the hood.
With familiarity of pattern matching, a user reading this function using <code class="docutils literal notranslate"><span class="pre">match</span></code>
will likely find this version clearer than the traditional approach.</p>
</section>
</section>
<section id="rationale-and-goals">
<h2><a class="toc-backref" href="#rationale-and-goals" role="doc-backlink">Rationale and Goals</a></h2>
<p>Python programs frequently need to handle data which varies in type,
presence of attributes/keys, or number of elements. Typical examples
are operating on nodes of a mixed structure like an AST, handling UI
events of different types, processing structured input (like
structured files or network messages), or “parsing” arguments for a
function that can accept different combinations of types and numbers
of parameters. In fact, the classic visitor pattern is an example of this,
done in an OOP style but matching makes it much less tedious to write.</p>
<p>Much of the code to do so tends to consist of complex chains of nested
<code class="docutils literal notranslate"><span class="pre">if</span></code>/<code class="docutils literal notranslate"><span class="pre">elif</span></code> statements, including multiple calls to <code class="docutils literal notranslate"><span class="pre">len()</span></code>,
<code class="docutils literal notranslate"><span class="pre">isinstance()</span></code> and index/key/attribute access. Inside those branches
users sometimes need to destructure the data further to extract the
required component values, which may be nested several objects deep.</p>
<p>Pattern matching as present in many other languages provides an
elegant solution to this problem. These range from statically compiled
functional languages like F# and Haskell, via mixed-paradigm languages
like <a class="reference external" href="https://docs.scala-lang.org/tour/pattern-matching.html">Scala</a> and <a class="reference external" href="https://doc.rust-lang.org/reference/patterns.html">Rust</a>, to dynamic languages like Elixir and
Ruby, and is under consideration for JavaScript. We are indebted to
these languages for guiding the way to Pythonic pattern matching, as
Python is indebted to so many other languages for many of its
features: many basic syntactic features were inherited from C,
exceptions from Modula-3, classes were inspired by C++, slicing came
from Icon, regular expressions from Perl, decorators resemble Java
annotations, and so on.</p>
<p>The usual logic for operating on heterogeneous data can be summarized
in the following way:</p>
<ul class="simple">
<li>Some analysis is done on the <em>shape</em> (type and components) of the
data: This could involve <code class="docutils literal notranslate"><span class="pre">isinstance()</span></code> or <code class="docutils literal notranslate"><span class="pre">len()</span></code> calls and/or extracting
components (via indexing or attribute access) which are checked for
specific values or conditions.</li>
<li>If the shape is as expected, some more components are possibly
extracted and some operation is done using the extracted values.</li>
</ul>
<p>Take for example <a class="reference external" href="https://github.com/django/django/blob/5166097d7c80cab757e44f2d02f3d148fbbc2ff6/django/db/models/enums.py#L13">this piece of the Django web framework</a>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="p">(</span>
<span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="p">(</span><span class="nb">list</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">))</span> <span class="ow">and</span>
<span class="nb">len</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span> <span class="ow">and</span>
<span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="p">(</span><span class="n">Promise</span><span class="p">,</span> <span class="nb">str</span><span class="p">))</span>
<span class="p">):</span>
<span class="o">*</span><span class="n">value</span><span class="p">,</span> <span class="n">label</span> <span class="o">=</span> <span class="n">value</span>
<span class="n">value</span> <span class="o">=</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">label</span> <span class="o">=</span> <span class="n">key</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;_&#39;</span><span class="p">,</span> <span class="s1">&#39; &#39;</span><span class="p">)</span><span class="o">.</span><span class="n">title</span><span class="p">()</span>
</pre></div>
</div>
<p>We can see the shape analysis of the <code class="docutils literal notranslate"><span class="pre">value</span></code> at the top, following
by the destructuring inside.</p>
<p>Note that shape analysis here involves checking the types both of the
container and of one of its components, and some checks on its number
of elements. Once we match the shape, we need to decompose the
sequence. With the proposal in this PEP, we could rewrite that code
into this:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">value</span><span class="p">:</span>
<span class="k">case</span> <span class="p">[</span><span class="o">*</span><span class="n">v</span><span class="p">,</span> <span class="n">label</span> <span class="o">:=</span> <span class="p">(</span><span class="n">Promise</span><span class="p">()</span> <span class="o">|</span> <span class="nb">str</span><span class="p">())]</span> <span class="k">if</span> <span class="n">v</span><span class="p">:</span>
<span class="n">value</span> <span class="o">=</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>
<span class="k">case</span><span class="w"> </span><span class="k">_</span><span class="p">:</span>
<span class="n">label</span> <span class="o">=</span> <span class="n">key</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;_&#39;</span><span class="p">,</span> <span class="s1">&#39; &#39;</span><span class="p">)</span><span class="o">.</span><span class="n">title</span><span class="p">()</span>
</pre></div>
</div>
<p>This syntax makes much more explicit which formats are possible for
the input data, and which components are extracted from where. You can
see a pattern similar to list unpacking, but also type checking: the
<code class="docutils literal notranslate"><span class="pre">Promise()</span></code> pattern is not an object construction, but represents
anything thats an instance of <code class="docutils literal notranslate"><span class="pre">Promise</span></code>. The pattern operator <code class="docutils literal notranslate"><span class="pre">|</span></code>
separates alternative patterns (not unlike regular expressions or EBNF
grammars), and <code class="docutils literal notranslate"><span class="pre">_</span></code> is a wildcard. (Note that the match syntax used
here will accept user-defined sequences, as well as lists and tuples.)</p>
<p>In some occasions, extraction of information is not as relevant as
identifying structure. Take the following example from the
<a class="reference external" href="https://github.com/python/cpython/blob/c4cacc8/Lib/lib2to3/fixer_util.py#L158">Python standard library</a>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">is_tuple</span><span class="p">(</span><span class="n">node</span><span class="p">):</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">Node</span><span class="p">)</span> <span class="ow">and</span> <span class="n">node</span><span class="o">.</span><span class="n">children</span> <span class="o">==</span> <span class="p">[</span><span class="n">LParen</span><span class="p">(),</span> <span class="n">RParen</span><span class="p">()]:</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="k">return</span> <span class="p">(</span><span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">Node</span><span class="p">)</span>
<span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">node</span><span class="o">.</span><span class="n">children</span><span class="p">)</span> <span class="o">==</span> <span class="mi">3</span>
<span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="o">.</span><span class="n">children</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">Leaf</span><span class="p">)</span>
<span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="o">.</span><span class="n">children</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">Node</span><span class="p">)</span>
<span class="ow">and</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="o">.</span><span class="n">children</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">Leaf</span><span class="p">)</span>
<span class="ow">and</span> <span class="n">node</span><span class="o">.</span><span class="n">children</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">value</span> <span class="o">==</span> <span class="s2">&quot;(&quot;</span>
<span class="ow">and</span> <span class="n">node</span><span class="o">.</span><span class="n">children</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="o">.</span><span class="n">value</span> <span class="o">==</span> <span class="s2">&quot;)&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>This example shows an example of finding out the “shape” of the data
without doing significant extraction. This code is not very easy to
read, and the intended shape that this is trying to match is not
evident. Compare with the updated code using the proposed syntax:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">is_tuple</span><span class="p">(</span><span class="n">node</span><span class="p">:</span> <span class="n">Node</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
<span class="k">match</span> <span class="n">node</span><span class="p">:</span>
<span class="k">case</span> <span class="n">Node</span><span class="p">(</span><span class="n">children</span><span class="o">=</span><span class="p">[</span><span class="n">LParen</span><span class="p">(),</span> <span class="n">RParen</span><span class="p">()]):</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="k">case</span> <span class="n">Node</span><span class="p">(</span><span class="n">children</span><span class="o">=</span><span class="p">[</span><span class="n">Leaf</span><span class="p">(</span><span class="n">value</span><span class="o">=</span><span class="s2">&quot;(&quot;</span><span class="p">),</span> <span class="n">Node</span><span class="p">(),</span> <span class="n">Leaf</span><span class="p">(</span><span class="n">value</span><span class="o">=</span><span class="s2">&quot;)&quot;</span><span class="p">)]):</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="k">case</span><span class="w"> </span><span class="k">_</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">False</span>
</pre></div>
</div>
<p>Note that the proposed code will work without any modifications to the
definition of <code class="docutils literal notranslate"><span class="pre">Node</span></code> and other classes here. As shown in the
examples above, the proposal supports not just unpacking sequences, but
also doing <code class="docutils literal notranslate"><span class="pre">isinstance</span></code> checks (like <code class="docutils literal notranslate"><span class="pre">LParen()</span></code> or <code class="docutils literal notranslate"><span class="pre">str()</span></code>),
looking into object attributes (<code class="docutils literal notranslate"><span class="pre">Leaf(value=&quot;(&quot;)</span></code> for example) and
comparisons with literals.</p>
<p>That last feature helps with some kinds of code which look more like
the “switch” statement as present in other languages:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">response</span><span class="o">.</span><span class="n">status</span><span class="p">:</span>
<span class="k">case</span> <span class="mi">200</span><span class="p">:</span>
<span class="n">do_something</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">data</span><span class="p">)</span> <span class="c1"># OK</span>
<span class="k">case</span> <span class="mi">301</span> <span class="o">|</span> <span class="mi">302</span><span class="p">:</span>
<span class="n">retry</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">location</span><span class="p">)</span> <span class="c1"># Redirect</span>
<span class="k">case</span> <span class="mi">401</span><span class="p">:</span>
<span class="n">retry</span><span class="p">(</span><span class="n">auth</span><span class="o">=</span><span class="n">get_credentials</span><span class="p">())</span> <span class="c1"># Login first</span>
<span class="k">case</span> <span class="mi">426</span><span class="p">:</span>
<span class="n">sleep</span><span class="p">(</span><span class="n">DELAY</span><span class="p">)</span> <span class="c1"># Server is swamped, try after a bit</span>
<span class="n">retry</span><span class="p">()</span>
<span class="k">case</span><span class="w"> </span><span class="k">_</span><span class="p">:</span>
<span class="k">raise</span> <span class="n">RequestError</span><span class="p">(</span><span class="s2">&quot;we couldn&#39;t get the data&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>Although this will work, its not necessarily what the proposal is
focused on, and the new syntax has been designed to best support the
destructuring scenarios.</p>
<p>See the <a class="reference internal" href="#syntax-and-semantics">syntax</a> sections below
for a more detailed specification.</p>
<p>We propose that destructuring objects can be customized by a new
special <code class="docutils literal notranslate"><span class="pre">__match_args__</span></code> attribute. As part of this PEP we specify
the general API and its implementation for some standard library
classes (including named tuples and dataclasses). See the <a class="reference internal" href="#runtime-specification">runtime</a> section below.</p>
<p>Finally, we aim to provide comprehensive support for static type
checkers and similar tools. For this purpose, we propose to introduce
a <code class="docutils literal notranslate"><span class="pre">&#64;typing.sealed</span></code> class decorator that will be a no-op at runtime
but will indicate to static tools that all sub-classes of this class
must be defined in the same module. This will allow effective static
exhaustiveness checks, and together with dataclasses, will provide
basic support for <a class="reference external" href="https://en.wikipedia.org/wiki/Algebraic_data_type">algebraic data types</a>. See the <a class="reference internal" href="#static-checkers-specification">static checkers</a> section for more details.</p>
</section>
<section id="syntax-and-semantics">
<h2><a class="toc-backref" href="#syntax-and-semantics" role="doc-backlink">Syntax and Semantics</a></h2>
<section id="patterns">
<h3><a class="toc-backref" href="#patterns" role="doc-backlink">Patterns</a></h3>
<p>The <strong>pattern</strong> is a new syntactic construct, that could be considered a loose
generalization of assignment targets. The key properties of a pattern are what
types and shapes of subjects it accepts, what variables it captures and how
it extracts them from the subject. For example, the pattern <code class="docutils literal notranslate"><span class="pre">[a,</span> <span class="pre">b]</span></code> matches
only sequences of exactly 2 elements, extracting the first element into <code class="docutils literal notranslate"><span class="pre">a</span></code>
and the second one into <code class="docutils literal notranslate"><span class="pre">b</span></code>.</p>
<p>This PEP defines several types of patterns. These are certainly not the
only possible ones, so the design decision was made to choose a subset of
functionality that is useful now but conservative. More patterns can be added
later as this feature gets more widespread use. See the <a class="reference internal" href="#rejected-ideas">rejected ideas</a>
and <a class="reference internal" href="#deferred-ideas">deferred ideas</a> sections for more details.</p>
<p>The patterns listed here are described in more detail below, but summarized
together in this section for simplicity:</p>
<ul class="simple">
<li>A <strong>literal pattern</strong> is useful to filter constant values in a structure.
It looks like a Python literal (including some values like <code class="docutils literal notranslate"><span class="pre">True</span></code>,
<code class="docutils literal notranslate"><span class="pre">False</span></code> and <code class="docutils literal notranslate"><span class="pre">None</span></code>). It only matches objects equal to the literal, and
never binds.</li>
<li>A <strong>capture pattern</strong> looks like <code class="docutils literal notranslate"><span class="pre">x</span></code> and is equivalent to an identical
assignment target: it always matches and binds the variable
with the given (simple) name.</li>
<li>The <strong>wildcard pattern</strong> is a single underscore: <code class="docutils literal notranslate"><span class="pre">_</span></code>. It always matches,
but does not capture any variable (which prevents interference with other
uses for <code class="docutils literal notranslate"><span class="pre">_</span></code> and allows for some optimizations).</li>
<li>A <strong>constant value pattern</strong> works like the literal but for certain named
constants. Note that it must be a qualified (dotted) name, given the possible
ambiguity with a capture pattern. It looks like <code class="docutils literal notranslate"><span class="pre">Color.RED</span></code> and
only matches values equal to the corresponding value. It never binds.</li>
<li>A <strong>sequence pattern</strong> looks like <code class="docutils literal notranslate"><span class="pre">[a,</span> <span class="pre">*rest,</span> <span class="pre">b]</span></code> and is similar to
a list unpacking. An important difference is that the elements nested
within it can be any kind of patterns, not just names or sequences.
It matches only sequences of appropriate length, as long as all the sub-patterns
also match. It makes all the bindings of its sub-patterns.</li>
<li>A <strong>mapping pattern</strong> looks like <code class="docutils literal notranslate"><span class="pre">{&quot;user&quot;:</span> <span class="pre">u,</span> <span class="pre">&quot;emails&quot;:</span> <span class="pre">[*es]}</span></code>. It matches
mappings with at least the set of provided keys, and if all the
sub-patterns match their corresponding values. It binds whatever the
sub-patterns bind while matching with the values corresponding to the keys.
Adding <code class="docutils literal notranslate"><span class="pre">**rest</span></code> at the end of the pattern to capture extra items is allowed.</li>
<li>A <strong>class pattern</strong> is similar to the above but matches attributes instead
of keys. It looks like <code class="docutils literal notranslate"><span class="pre">datetime.date(year=y,</span> <span class="pre">day=d)</span></code>. It matches
instances of the given type, having at least the specified
attributes, as long as the attributes match with the corresponding
sub-patterns. It binds whatever the sub-patterns bind when matching with the
values of
the given attributes. An optional protocol also allows matching positional
arguments.</li>
<li>An <strong>OR pattern</strong> looks like <code class="docutils literal notranslate"><span class="pre">[*x]</span> <span class="pre">|</span> <span class="pre">{&quot;elems&quot;:</span> <span class="pre">[*x]}</span></code>. It matches if any
of its sub-patterns match. It uses the binding for the leftmost pattern
that matched.</li>
<li>A <strong>walrus pattern</strong> looks like <code class="docutils literal notranslate"><span class="pre">d</span> <span class="pre">:=</span> <span class="pre">datetime(year=2020,</span> <span class="pre">month=m)</span></code>. It
matches only
if its sub-pattern also matches. It binds whatever the sub-pattern match does, and
also binds the named variable to the entire object.</li>
</ul>
</section>
<section id="the-match-statement">
<h3><a class="toc-backref" href="#the-match-statement" role="doc-backlink">The <code class="docutils literal notranslate"><span class="pre">match</span></code> statement</a></h3>
<p>A simplified, approximate grammar for the proposed syntax is:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">...</span>
<span class="n">compound_statement</span><span class="p">:</span>
<span class="o">|</span> <span class="n">if_stmt</span>
<span class="o">...</span>
<span class="o">|</span> <span class="n">match_stmt</span>
<span class="n">match_stmt</span><span class="p">:</span> <span class="s2">&quot;match&quot;</span> <span class="n">expression</span> <span class="s1">&#39;:&#39;</span> <span class="n">NEWLINE</span> <span class="n">INDENT</span> <span class="n">case_block</span><span class="o">+</span> <span class="n">DEDENT</span>
<span class="n">case_block</span><span class="p">:</span> <span class="s2">&quot;case&quot;</span> <span class="n">pattern</span> <span class="p">[</span><span class="n">guard</span><span class="p">]</span> <span class="s1">&#39;:&#39;</span> <span class="n">block</span>
<span class="n">guard</span><span class="p">:</span> <span class="s1">&#39;if&#39;</span> <span class="n">expression</span>
<span class="n">pattern</span><span class="p">:</span> <span class="n">walrus_pattern</span> <span class="o">|</span> <span class="n">or_pattern</span>
<span class="n">walrus_pattern</span><span class="p">:</span> <span class="n">NAME</span> <span class="s1">&#39;:=&#39;</span> <span class="n">or_pattern</span>
<span class="n">or_pattern</span><span class="p">:</span> <span class="n">closed_pattern</span> <span class="p">(</span><span class="s1">&#39;|&#39;</span> <span class="n">closed_pattern</span><span class="p">)</span><span class="o">*</span>
<span class="n">closed_pattern</span><span class="p">:</span>
<span class="o">|</span> <span class="n">literal_pattern</span>
<span class="o">|</span> <span class="n">capture_pattern</span>
<span class="o">|</span> <span class="n">wildcard_pattern</span>
<span class="o">|</span> <span class="n">constant_pattern</span>
<span class="o">|</span> <span class="n">sequence_pattern</span>
<span class="o">|</span> <span class="n">mapping_pattern</span>
<span class="o">|</span> <span class="n">class_pattern</span>
</pre></div>
</div>
<p>See <a class="reference internal" href="#appendix-a-full-grammar">Appendix A</a> for the full, unabridged grammar.
The simplified grammars in this section are there for helping the reader,
not as a full specification.</p>
<p>We propose that the match operation should be a statement, not an expression.
Although in
many languages it is an expression, being a statement better suits the general
logic of Python syntax. See <a class="reference internal" href="#rejected-ideas">rejected ideas</a> for more discussion.
The allowed patterns are described in detail below in the <a class="reference internal" href="#allowed-patterns">patterns</a> subsection.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">match</span></code> and <code class="docutils literal notranslate"><span class="pre">case</span></code> keywords are proposed to be soft keywords,
so that they are recognized as keywords at the beginning of a match
statement or case block respectively, but are allowed to be used in
other places as variable or argument names.</p>
<p>The proposed indentation structure is as following:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">some_expression</span><span class="p">:</span>
<span class="k">case</span> <span class="n">pattern_1</span><span class="p">:</span>
<span class="o">...</span>
<span class="k">case</span> <span class="n">pattern_2</span><span class="p">:</span>
<span class="o">...</span>
</pre></div>
</div>
<p>Here, <code class="docutils literal notranslate"><span class="pre">some_expression</span></code> represents the value that is being matched against,
which will be referred to hereafter as the <em>subject</em> of the match.</p>
</section>
<section id="match-semantics">
<h3><a class="toc-backref" href="#match-semantics" role="doc-backlink">Match semantics</a></h3>
<p>The proposed large scale semantics for choosing the match is to choose the first
matching pattern and execute the corresponding suite. The remaining patterns
are not tried. If there are no matching patterns, the statement falls
through, and execution continues at the following statement.</p>
<p>Essentially this is equivalent to a chain of <code class="docutils literal notranslate"><span class="pre">if</span> <span class="pre">...</span> <span class="pre">elif</span> <span class="pre">...</span> <span class="pre">else</span></code>
statements. Note that unlike for the previously proposed <code class="docutils literal notranslate"><span class="pre">switch</span></code> statement,
the pre-computed dispatch dictionary semantics does not apply here.</p>
<p>There is no <code class="docutils literal notranslate"><span class="pre">default</span></code> or <code class="docutils literal notranslate"><span class="pre">else</span></code> case - instead the special wildcard
<code class="docutils literal notranslate"><span class="pre">_</span></code> can be used (see the section on <a class="reference internal" href="#capture-patterns">capture_pattern</a>)
as a final catch-all pattern.</p>
<p>Name bindings made during a successful pattern match outlive the executed suite
and can be used after the match statement. This follows the logic of other
Python statements that can bind names, such as <code class="docutils literal notranslate"><span class="pre">for</span></code> loop and <code class="docutils literal notranslate"><span class="pre">with</span></code>
statement. For example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">shape</span><span class="p">:</span>
<span class="k">case</span> <span class="n">Point</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="o">...</span>
<span class="k">case</span><span class="w"> </span><span class="n">Rectangle</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="k">_</span><span class="p">,</span> <span class="n">_</span><span class="p">):</span>
<span class="o">...</span>
<span class="nb">print</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="c1"># This works</span>
</pre></div>
</div>
<p>During failed pattern matches, some sub-patterns may succeed. For example,
while matching the value <code class="docutils literal notranslate"><span class="pre">[0,</span> <span class="pre">1,</span> <span class="pre">2]</span></code> with the pattern <code class="docutils literal notranslate"><span class="pre">(0,</span> <span class="pre">x,</span> <span class="pre">1)</span></code>, the
sub-pattern <code class="docutils literal notranslate"><span class="pre">x</span></code> may succeed if the list elements are matched from left to right.
The implementation may choose to either make persistent bindings for those
partial matches or not. User code including a <code class="docutils literal notranslate"><span class="pre">match</span></code> statement should not rely
on the bindings being made for a failed match, but also shouldnt assume that
variables are unchanged by a failed match. This part of the behavior is
left intentionally unspecified so different implementations can add
optimizations, and to prevent introducing semantic restrictions that could
limit the extensibility of this feature.</p>
<p>Note that some pattern types below define more specific rules about when
the binding is made.</p>
</section>
<section id="allowed-patterns">
<span id="id1"></span><h3><a class="toc-backref" href="#allowed-patterns" role="doc-backlink">Allowed patterns</a></h3>
<p>We introduce the proposed syntax gradually. Here we start from the main
building blocks. The following patterns are supported:</p>
<section id="literal-patterns">
<h4><a class="toc-backref" href="#literal-patterns" role="doc-backlink">Literal Patterns</a></h4>
<p>Simplified syntax:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">literal_pattern</span><span class="p">:</span>
<span class="o">|</span> <span class="n">number</span>
<span class="o">|</span> <span class="n">string</span>
<span class="o">|</span> <span class="s1">&#39;None&#39;</span>
<span class="o">|</span> <span class="s1">&#39;True&#39;</span>
<span class="o">|</span> <span class="s1">&#39;False&#39;</span>
</pre></div>
</div>
<p>A literal pattern consists of a simple literal like a string, a number,
a Boolean literal (<code class="docutils literal notranslate"><span class="pre">True</span></code> or <code class="docutils literal notranslate"><span class="pre">False</span></code>), or <code class="docutils literal notranslate"><span class="pre">None</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">number</span><span class="p">:</span>
<span class="k">case</span> <span class="mi">0</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Nothing&quot;</span><span class="p">)</span>
<span class="k">case</span> <span class="mi">1</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Just one&quot;</span><span class="p">)</span>
<span class="k">case</span> <span class="mi">2</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;A couple&quot;</span><span class="p">)</span>
<span class="k">case</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;One less than nothing&quot;</span><span class="p">)</span>
<span class="k">case</span> <span class="mi">1</span><span class="o">-</span><span class="mi">1</span><span class="n">j</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Good luck with that...&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>Literal pattern uses equality with literal on the right hand side, so that
in the above example <code class="docutils literal notranslate"><span class="pre">number</span> <span class="pre">==</span> <span class="pre">0</span></code> and then possibly <code class="docutils literal notranslate"><span class="pre">number</span> <span class="pre">==</span> <span class="pre">1</span></code>, etc
will be evaluated. Note that although technically negative numbers
are represented using unary minus, they are considered
literals for the purpose of pattern matching. Unary plus is not allowed.
Binary plus and minus are allowed only to join a real number and an imaginary
number to form a complex number, such as <code class="docutils literal notranslate"><span class="pre">1+1j</span></code>.</p>
<p>Note that because equality (<code class="docutils literal notranslate"><span class="pre">__eq__</span></code>) is used, and the equivalency
between Booleans and the integers <code class="docutils literal notranslate"><span class="pre">0</span></code> and <code class="docutils literal notranslate"><span class="pre">1</span></code>, there is no
practical difference between the following two:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">case</span> <span class="kc">True</span><span class="p">:</span>
<span class="o">...</span>
<span class="k">case</span> <span class="mi">1</span><span class="p">:</span>
<span class="o">...</span>
</pre></div>
</div>
<p>Triple-quoted strings are supported. Raw strings and byte strings
are supported. F-strings are not allowed (since in general they are not
really literals).</p>
</section>
<section id="capture-patterns">
<h4><a class="toc-backref" href="#capture-patterns" role="doc-backlink">Capture Patterns</a></h4>
<p>Simplified syntax:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">capture_pattern</span><span class="p">:</span> <span class="n">NAME</span>
</pre></div>
</div>
<p>A capture pattern serves as an assignment target for the matched expression:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">greeting</span><span class="p">:</span>
<span class="k">case</span> <span class="s2">&quot;&quot;</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Hello!&quot;</span><span class="p">)</span>
<span class="k">case</span> <span class="n">name</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Hi </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">!&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>Only a single name is allowed (a dotted name is a constant value pattern).
A capture pattern always succeeds. A capture pattern appearing in a scope makes
the name local to that scope. For example, using <code class="docutils literal notranslate"><span class="pre">name</span></code> after the above
snippet may raise <code class="docutils literal notranslate"><span class="pre">UnboundLocalError</span></code> rather than <code class="docutils literal notranslate"><span class="pre">NameError</span></code>, if
the <code class="docutils literal notranslate"><span class="pre">&quot;&quot;</span></code> case clause was taken:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">greeting</span><span class="p">:</span>
<span class="k">case</span> <span class="s2">&quot;&quot;</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Hello!&quot;</span><span class="p">)</span>
<span class="k">case</span> <span class="n">name</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Hi </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">!&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">name</span> <span class="o">==</span> <span class="s2">&quot;Santa&quot;</span><span class="p">:</span> <span class="c1"># &lt;-- might raise UnboundLocalError</span>
<span class="o">...</span> <span class="c1"># but works fine if greeting was not empty</span>
</pre></div>
</div>
<p>While matching against each case clause, a name may be bound at most
once, having two capture patterns with coinciding names is an error:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">data</span><span class="p">:</span>
<span class="k">case</span> <span class="p">[</span><span class="n">x</span><span class="p">,</span> <span class="n">x</span><span class="p">]:</span> <span class="c1"># Error!</span>
<span class="o">...</span>
</pre></div>
</div>
<p>Note: one can still match on a collection with equal items using <a class="reference internal" href="#guards">guards</a>.
Also, <code class="docutils literal notranslate"><span class="pre">[x,</span> <span class="pre">y]</span> <span class="pre">|</span> <span class="pre">Point(x,</span> <span class="pre">y)</span></code> is a legal pattern because the two
alternatives are never matched at the same time.</p>
<p>The single underscore (<code class="docutils literal notranslate"><span class="pre">_</span></code>) is not considered a <code class="docutils literal notranslate"><span class="pre">NAME</span></code> and treated specially
as a <a class="reference internal" href="#wildcard-pattern">wildcard pattern</a>.</p>
<p>Reminder: <code class="docutils literal notranslate"><span class="pre">None</span></code>, <code class="docutils literal notranslate"><span class="pre">False</span></code> and <code class="docutils literal notranslate"><span class="pre">True</span></code> are keywords denoting
literals, not names.</p>
</section>
<section id="wildcard-pattern">
<h4><a class="toc-backref" href="#wildcard-pattern" role="doc-backlink">Wildcard Pattern</a></h4>
<p>Simplified syntax:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">wildcard_pattern</span><span class="p">:</span> <span class="s2">&quot;_&quot;</span>
</pre></div>
</div>
<p>The single underscore (<code class="docutils literal notranslate"><span class="pre">_</span></code>) name is a special kind of pattern that always
matches but <em>never</em> binds:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">data</span><span class="p">:</span>
<span class="k">case</span><span class="w"> </span><span class="p">[</span><span class="k">_</span><span class="p">,</span> <span class="n">_</span><span class="p">]:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Some pair&quot;</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">_</span><span class="p">)</span> <span class="c1"># Error!</span>
</pre></div>
</div>
<p>Given that no binding is made, it can be used as many times as desired, unlike
capture patterns.</p>
</section>
<section id="constant-value-patterns">
<h4><a class="toc-backref" href="#constant-value-patterns" role="doc-backlink">Constant Value Patterns</a></h4>
<p>Simplified syntax:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">constant_pattern</span><span class="p">:</span> <span class="n">NAME</span> <span class="p">(</span><span class="s1">&#39;.&#39;</span> <span class="n">NAME</span><span class="p">)</span><span class="o">+</span>
</pre></div>
</div>
<p>This is used to match against constants and enum values.
Every dotted name in a pattern is looked up using normal Python name
resolution rules, and the value is used for comparison by equality with
the match subject (same as for literals):</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">enum</span> <span class="kn">import</span> <span class="n">Enum</span>
<span class="k">class</span> <span class="nc">Sides</span><span class="p">(</span><span class="nb">str</span><span class="p">,</span> <span class="n">Enum</span><span class="p">):</span>
<span class="n">SPAM</span> <span class="o">=</span> <span class="s2">&quot;Spam&quot;</span>
<span class="n">EGGS</span> <span class="o">=</span> <span class="s2">&quot;eggs&quot;</span>
<span class="o">...</span>
<span class="k">match</span> <span class="n">entree</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]:</span>
<span class="k">case</span> <span class="n">Sides</span><span class="o">.</span><span class="n">SPAM</span><span class="p">:</span> <span class="c1"># Compares entree[-1] == Sides.SPAM.</span>
<span class="n">response</span> <span class="o">=</span> <span class="s2">&quot;Have you got anything without Spam?&quot;</span>
<span class="k">case</span> <span class="n">side</span><span class="p">:</span> <span class="c1"># Assigns side = entree[-1].</span>
<span class="n">response</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;Well, could I have their Spam instead of the </span><span class="si">{</span><span class="n">side</span><span class="si">}</span><span class="s2"> then?&quot;</span>
</pre></div>
</div>
<p>Note that there is no way to use unqualified names as constant value
patterns (they always denote variables to be captured). See
<a class="reference internal" href="#rejected-ideas">rejected ideas</a> for other syntactic alternatives that were
considered for constant value patterns.</p>
</section>
<section id="sequence-patterns">
<h4><a class="toc-backref" href="#sequence-patterns" role="doc-backlink">Sequence Patterns</a></h4>
<p>Simplified syntax:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>sequence_pattern:
| &#39;[&#39; [values_pattern] &#39;]&#39;
| &#39;(&#39; [value_pattern &#39;,&#39; [values pattern]] &#39;)&#39;
values_pattern: &#39;,&#39;.value_pattern+ &#39;,&#39;?
value_pattern: &#39;*&#39; capture_pattern | pattern
</pre></div>
</div>
<p>A sequence pattern follows the same semantics as unpacking assignment.
Like unpacking assignment, both tuple-like and list-like syntax can be
used, with identical semantics. Each element can be an arbitrary
pattern; there may also be at most one <code class="docutils literal notranslate"><span class="pre">*name</span></code> pattern to catch all
remaining items:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">collection</span><span class="p">:</span>
<span class="k">case</span> <span class="mi">1</span><span class="p">,</span> <span class="p">[</span><span class="n">x</span><span class="p">,</span> <span class="o">*</span><span class="n">others</span><span class="p">]:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Got 1 and a nested sequence&quot;</span><span class="p">)</span>
<span class="k">case</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Got 1 and </span><span class="si">{</span><span class="n">x</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>To match a sequence pattern the subject must be an instance of
<code class="docutils literal notranslate"><span class="pre">collections.abc.Sequence</span></code>, and it cannot be any kind of string
(<code class="docutils literal notranslate"><span class="pre">str</span></code>, <code class="docutils literal notranslate"><span class="pre">bytes</span></code>, <code class="docutils literal notranslate"><span class="pre">bytearray</span></code>). It cannot be an iterator. For matching
on a specific collection class, see class pattern below.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">_</span></code> wildcard can be starred to match sequences of varying lengths. For
example:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">[*_]</span></code> matches a sequence of any length.</li>
<li><code class="docutils literal notranslate"><span class="pre">(_,</span> <span class="pre">_,</span> <span class="pre">*_)</span></code>, matches any sequence of length two or more.</li>
<li><code class="docutils literal notranslate"><span class="pre">[&quot;a&quot;,</span> <span class="pre">*_,</span> <span class="pre">&quot;z&quot;]</span></code> matches any sequence of length two or more that starts with
<code class="docutils literal notranslate"><span class="pre">&quot;a&quot;</span></code> and ends with <code class="docutils literal notranslate"><span class="pre">&quot;z&quot;</span></code>.</li>
</ul>
</section>
<section id="mapping-patterns">
<h4><a class="toc-backref" href="#mapping-patterns" role="doc-backlink">Mapping Patterns</a></h4>
<p>Simplified syntax:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>mapping_pattern: &#39;{&#39; [items_pattern] &#39;}&#39;
items_pattern: &#39;,&#39;.key_value_pattern+ &#39;,&#39;?
key_value_pattern:
| (literal_pattern | constant_pattern) &#39;:&#39; or_pattern
| &#39;**&#39; capture_pattern
</pre></div>
</div>
<p>Mapping pattern is a generalization of iterable unpacking to mappings.
Its syntax is similar to dictionary display but each key and value are
patterns <code class="docutils literal notranslate"><span class="pre">&quot;{&quot;</span> <span class="pre">(pattern</span> <span class="pre">&quot;:&quot;</span> <span class="pre">pattern)+</span> <span class="pre">&quot;}&quot;</span></code>. A <code class="docutils literal notranslate"><span class="pre">**rest</span></code> pattern is also
allowed, to extract the remaining items. Only literal and constant value
patterns are allowed in key positions:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">constants</span>
<span class="k">match</span> <span class="n">config</span><span class="p">:</span>
<span class="k">case</span> <span class="p">{</span><span class="s2">&quot;route&quot;</span><span class="p">:</span> <span class="n">route</span><span class="p">}:</span>
<span class="n">process_route</span><span class="p">(</span><span class="n">route</span><span class="p">)</span>
<span class="k">case</span> <span class="p">{</span><span class="n">constants</span><span class="o">.</span><span class="n">DEFAULT_PORT</span><span class="p">:</span> <span class="n">sub_config</span><span class="p">,</span> <span class="o">**</span><span class="n">rest</span><span class="p">}:</span>
<span class="n">process_config</span><span class="p">(</span><span class="n">sub_config</span><span class="p">,</span> <span class="n">rest</span><span class="p">)</span>
</pre></div>
</div>
<p>The subject must be an instance of <code class="docutils literal notranslate"><span class="pre">collections.abc.Mapping</span></code>.
Extra keys in the subject are ignored even if <code class="docutils literal notranslate"><span class="pre">**rest</span></code> is not present.
This is different from sequence pattern, where extra items will cause a
match to fail. But mappings are actually different from sequences: they
have natural structural sub-typing behavior, i.e., passing a dictionary
with extra keys somewhere will likely just work.</p>
<p>For this reason, <code class="docutils literal notranslate"><span class="pre">**_</span></code> is invalid in mapping patterns; it would always be a
no-op that could be removed without consequence.</p>
<p>Matched key-value pairs must already be present in the mapping, and not created
on-the-fly by <code class="docutils literal notranslate"><span class="pre">__missing__</span></code> or <code class="docutils literal notranslate"><span class="pre">__getitem__</span></code>. For example,
<code class="docutils literal notranslate"><span class="pre">collections.defaultdict</span></code> instances will only match patterns with keys that
were already present when the <code class="docutils literal notranslate"><span class="pre">match</span></code> block was entered.</p>
</section>
<section id="class-patterns">
<h4><a class="toc-backref" href="#class-patterns" role="doc-backlink">Class Patterns</a></h4>
<p>Simplified syntax:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>class_pattern:
| name_or_attr &#39;(&#39; &#39;)&#39;
| name_or_attr &#39;(&#39; &#39;,&#39;.pattern+ &#39;,&#39;? &#39;)&#39;
| name_or_attr &#39;(&#39; &#39;,&#39;.keyword_pattern+ &#39;,&#39;? &#39;)&#39;
| name_or_attr &#39;(&#39; &#39;,&#39;.pattern+ &#39;,&#39; &#39;,&#39;.keyword_pattern+ &#39;,&#39;? &#39;)&#39;
keyword_pattern: NAME &#39;=&#39; or_pattern
</pre></div>
</div>
<p>A class pattern provides support for destructuring arbitrary objects.
There are two possible ways of matching on object attributes: by position
like <code class="docutils literal notranslate"><span class="pre">Point(1,</span> <span class="pre">2)</span></code>, and by name like <code class="docutils literal notranslate"><span class="pre">Point(x=1,</span> <span class="pre">y=2)</span></code>. These
two can be combined, but a positional match cannot follow a match by name.
Each item in a class pattern can be an arbitrary pattern. A simple
example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">shape</span><span class="p">:</span>
<span class="k">case</span> <span class="n">Point</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="o">...</span>
<span class="k">case</span> <span class="n">Rectangle</span><span class="p">(</span><span class="n">x0</span><span class="p">,</span> <span class="n">y0</span><span class="p">,</span> <span class="n">x1</span><span class="p">,</span> <span class="n">y1</span><span class="p">,</span> <span class="n">painted</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
<span class="o">...</span>
</pre></div>
</div>
<p>Whether a match succeeds or not is determined by the equivalent of an
<code class="docutils literal notranslate"><span class="pre">isinstance</span></code> call. If the subject (<code class="docutils literal notranslate"><span class="pre">shape</span></code>, in the example) is not
an instance of the named class (<code class="docutils literal notranslate"><span class="pre">Point</span></code> or <code class="docutils literal notranslate"><span class="pre">Rectangle</span></code>), the match
fails. Otherwise, it continues (see details in the <a class="reference internal" href="#runtime-specification">runtime</a> section).</p>
<p>The named class must inherit from <code class="docutils literal notranslate"><span class="pre">type</span></code>. It may be a single name
or a dotted name (e.g. <code class="docutils literal notranslate"><span class="pre">some_mod.SomeClass</span></code> or <code class="docutils literal notranslate"><span class="pre">mod.pkg.Class</span></code>).
The leading name must not be <code class="docutils literal notranslate"><span class="pre">_</span></code>, so e.g. <code class="docutils literal notranslate"><span class="pre">_(...)</span></code> and
<code class="docutils literal notranslate"><span class="pre">_.C(...)</span></code> are invalid. Use <code class="docutils literal notranslate"><span class="pre">object(foo=_)</span></code> to check whether the
matched object has an attribute <code class="docutils literal notranslate"><span class="pre">foo</span></code>.</p>
<p>By default, sub-patterns may only be matched by keyword for
user-defined classes. In order to support positional sub-patterns, a
custom <code class="docutils literal notranslate"><span class="pre">__match_args__</span></code> attribute is required.
The runtime allows matching against
arbitrarily nested patterns by chaining all of the instance checks and
attribute lookups appropriately.</p>
</section>
</section>
<section id="combining-multiple-patterns-or-patterns">
<h3><a class="toc-backref" href="#combining-multiple-patterns-or-patterns" role="doc-backlink">Combining multiple patterns (OR patterns)</a></h3>
<p>Multiple alternative patterns can be combined into one using <code class="docutils literal notranslate"><span class="pre">|</span></code>. This means
the whole pattern matches if at least one alternative matches.
Alternatives are tried from left to right and have a short-circuit property,
subsequent patterns are not tried if one matched. Examples:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">something</span><span class="p">:</span>
<span class="k">case</span> <span class="mi">0</span> <span class="o">|</span> <span class="mi">1</span> <span class="o">|</span> <span class="mi">2</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Small number&quot;</span><span class="p">)</span>
<span class="k">case</span><span class="w"> </span><span class="p">[]</span> <span class="o">|</span> <span class="p">[</span><span class="k">_</span><span class="p">]:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;A short sequence&quot;</span><span class="p">)</span>
<span class="k">case</span> <span class="nb">str</span><span class="p">()</span> <span class="o">|</span> <span class="nb">bytes</span><span class="p">():</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Something string-like&quot;</span><span class="p">)</span>
<span class="k">case</span><span class="w"> </span><span class="k">_</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Something else&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>The alternatives may bind variables, as long as each alternative binds
the same set of variables (excluding <code class="docutils literal notranslate"><span class="pre">_</span></code>). For example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">something</span><span class="p">:</span>
<span class="k">case</span> <span class="mi">1</span> <span class="o">|</span> <span class="n">x</span><span class="p">:</span> <span class="c1"># Error!</span>
<span class="o">...</span>
<span class="k">case</span> <span class="n">x</span> <span class="o">|</span> <span class="mi">1</span><span class="p">:</span> <span class="c1"># Error!</span>
<span class="o">...</span>
<span class="k">case</span> <span class="n">one</span> <span class="o">:=</span> <span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">|</span> <span class="n">two</span> <span class="o">:=</span> <span class="p">[</span><span class="mi">2</span><span class="p">]:</span> <span class="c1"># Error!</span>
<span class="o">...</span>
<span class="k">case</span> <span class="n">Foo</span><span class="p">(</span><span class="n">arg</span><span class="o">=</span><span class="n">x</span><span class="p">)</span> <span class="o">|</span> <span class="n">Bar</span><span class="p">(</span><span class="n">arg</span><span class="o">=</span><span class="n">x</span><span class="p">):</span> <span class="c1"># Valid, both arms bind &#39;x&#39;</span>
<span class="o">...</span>
<span class="k">case</span> <span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">|</span> <span class="n">x</span><span class="p">:</span> <span class="c1"># Valid, both arms bind &#39;x&#39;</span>
<span class="o">...</span>
</pre></div>
</div>
</section>
<section id="guards">
<h3><a class="toc-backref" href="#guards" role="doc-backlink">Guards</a></h3>
<p>Each <em>top-level</em> pattern can be followed by a <strong>guard</strong> of the form
<code class="docutils literal notranslate"><span class="pre">if</span> <span class="pre">expression</span></code>. A case clause succeeds if the pattern matches and the guard
evaluates to a true value. For example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="nb">input</span><span class="p">:</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="k">if</span> <span class="n">x</span> <span class="o">&gt;</span> <span class="n">MAX_INT</span> <span class="ow">and</span> <span class="n">y</span> <span class="o">&gt;</span> <span class="n">MAX_INT</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Got a pair of large numbers&quot;</span><span class="p">)</span>
<span class="k">case</span> <span class="n">x</span> <span class="k">if</span> <span class="n">x</span> <span class="o">&gt;</span> <span class="n">MAX_INT</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Got a large number&quot;</span><span class="p">)</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="k">if</span> <span class="n">x</span> <span class="o">==</span> <span class="n">y</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Got equal items&quot;</span><span class="p">)</span>
<span class="k">case</span><span class="w"> </span><span class="k">_</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Not an outstanding input&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>If evaluating a guard raises an exception, it is propagated onwards rather
than fail the case clause. Names that appear in a pattern are bound before the
guard succeeds. So this will work:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">values</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">match</span> <span class="n">values</span><span class="p">:</span>
<span class="k">case</span> <span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="k">if</span> <span class="n">x</span><span class="p">:</span>
<span class="o">...</span> <span class="c1"># This is not executed</span>
<span class="k">case</span><span class="w"> </span><span class="k">_</span><span class="p">:</span>
<span class="o">...</span>
<span class="nb">print</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="c1"># This will print &quot;0&quot;</span>
</pre></div>
</div>
<p>Note that guards are not allowed for nested patterns, so that <code class="docutils literal notranslate"><span class="pre">[x</span> <span class="pre">if</span> <span class="pre">x</span> <span class="pre">&gt;</span> <span class="pre">0]</span></code>
is a <code class="docutils literal notranslate"><span class="pre">SyntaxError</span></code> and <code class="docutils literal notranslate"><span class="pre">1</span> <span class="pre">|</span> <span class="pre">2</span> <span class="pre">if</span> <span class="pre">3</span> <span class="pre">|</span> <span class="pre">4</span></code> will be parsed as
<code class="docutils literal notranslate"><span class="pre">(1</span> <span class="pre">|</span> <span class="pre">2)</span> <span class="pre">if</span> <span class="pre">(3</span> <span class="pre">|</span> <span class="pre">4)</span></code>.</p>
</section>
<section id="walrus-patterns">
<h3><a class="toc-backref" href="#walrus-patterns" role="doc-backlink">Walrus patterns</a></h3>
<p>It is often useful to match a sub-pattern <em>and</em> bind the corresponding
value to a name. For example, it can be useful to write more efficient
matches, or simply to avoid repetition. To simplify such cases, any pattern
(other than the walrus pattern itself) can be preceded by a name and
the walrus operator (<code class="docutils literal notranslate"><span class="pre">:=</span></code>). For example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">get_shape</span><span class="p">():</span>
<span class="k">case</span> <span class="n">Line</span><span class="p">(</span><span class="n">start</span> <span class="o">:=</span> <span class="n">Point</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">end</span><span class="p">)</span> <span class="k">if</span> <span class="n">start</span> <span class="o">==</span> <span class="n">end</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Zero length line at </span><span class="si">{</span><span class="n">x</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">y</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>The name on the left of the walrus operator can be used in a guard, in
the match suite, or after the match statement. However, the name will
<em>only</em> be bound if the sub-pattern succeeds. Another example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">group_shapes</span><span class="p">():</span>
<span class="k">case</span> <span class="p">[],</span> <span class="p">[</span><span class="n">point</span> <span class="o">:=</span> <span class="n">Point</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="o">*</span><span class="n">other</span><span class="p">]:</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Got </span><span class="si">{</span><span class="n">point</span><span class="si">}</span><span class="s2"> in the second group&quot;</span><span class="p">)</span>
<span class="n">process_coordinates</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="o">...</span>
</pre></div>
</div>
<p>Technically, most such examples can be rewritten using guards and/or nested
match statements, but this will be less readable and/or will produce less
efficient code. Essentially, most of the arguments in <a class="pep reference internal" href="../pep-0572/" title="PEP 572 Assignment Expressions">PEP 572</a> apply here
equally.</p>
<p>The wildcard <code class="docutils literal notranslate"><span class="pre">_</span></code> is not a valid name here.</p>
</section>
</section>
<section id="runtime-specification">
<h2><a class="toc-backref" href="#runtime-specification" role="doc-backlink">Runtime specification</a></h2>
<section id="the-match-protocol">
<h3><a class="toc-backref" href="#the-match-protocol" role="doc-backlink">The Match Protocol</a></h3>
<p>The equivalent of an <code class="docutils literal notranslate"><span class="pre">isinstance</span></code> call is used to decide whether an
object matches a given class pattern and to extract the corresponding
attributes. Classes requiring different matching semantics (such as
duck-typing) can do so by defining <code class="docutils literal notranslate"><span class="pre">__instancecheck__</span></code> (a
pre-existing metaclass hook) or by using <code class="docutils literal notranslate"><span class="pre">typing.Protocol</span></code>.</p>
<p>The procedure is as following:</p>
<ul class="simple">
<li>The class object for <code class="docutils literal notranslate"><span class="pre">Class</span></code> in <code class="docutils literal notranslate"><span class="pre">Class(&lt;sub-patterns&gt;)</span></code> is
looked up and <code class="docutils literal notranslate"><span class="pre">isinstance(obj,</span> <span class="pre">Class)</span></code> is called, where <code class="docutils literal notranslate"><span class="pre">obj</span></code> is
the value being matched. If false, the match fails.</li>
<li>Otherwise, if any sub-patterns are given in the form of positional
or keyword arguments, these are matched from left to right, as
follows. The match fails as soon as a sub-pattern fails; if all
sub-patterns succeed, the overall class pattern match succeeds.</li>
<li>If there are match-by-position items and the class has a
<code class="docutils literal notranslate"><span class="pre">__match_args__</span></code> attribute, the item at position <code class="docutils literal notranslate"><span class="pre">i</span></code>
is matched against the value looked up by attribute
<code class="docutils literal notranslate"><span class="pre">__match_args__[i]</span></code>. For example, a pattern <code class="docutils literal notranslate"><span class="pre">Point2d(5,</span> <span class="pre">8)</span></code>,
where <code class="docutils literal notranslate"><span class="pre">Point2d.__match_args__</span> <span class="pre">==</span> <span class="pre">[&quot;x&quot;,</span> <span class="pre">&quot;y&quot;]</span></code>, is translated
(approximately) into <code class="docutils literal notranslate"><span class="pre">obj.x</span> <span class="pre">==</span> <span class="pre">5</span> <span class="pre">and</span> <span class="pre">obj.y</span> <span class="pre">==</span> <span class="pre">8</span></code>.</li>
<li>If there are more positional items than the length of
<code class="docutils literal notranslate"><span class="pre">__match_args__</span></code>, a <code class="docutils literal notranslate"><span class="pre">TypeError</span></code> is raised.</li>
<li>If the <code class="docutils literal notranslate"><span class="pre">__match_args__</span></code> attribute is absent on the matched class,
and one or more positional item appears in a match,
<code class="docutils literal notranslate"><span class="pre">TypeError</span></code> is also raised. We dont fall back on
using <code class="docutils literal notranslate"><span class="pre">__slots__</span></code> or <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> “In the face of ambiguity,
refuse the temptation to guess.”</li>
<li>If there are any match-by-keyword items the keywords are looked up
as attributes on the subject. If the lookup succeeds the value is
matched against the corresponding sub-pattern. If the lookup fails,
the match fails.</li>
</ul>
<p>Such a protocol favors simplicity of implementation over flexibility and
performance. For other considered alternatives, see <a class="reference internal" href="#extended-matching">extended matching</a>.</p>
<p>For the most commonly-matched built-in types (<code class="docutils literal notranslate"><span class="pre">bool</span></code>,
<code class="docutils literal notranslate"><span class="pre">bytearray</span></code>, <code class="docutils literal notranslate"><span class="pre">bytes</span></code>, <code class="docutils literal notranslate"><span class="pre">dict</span></code>, <code class="docutils literal notranslate"><span class="pre">float</span></code>,
<code class="docutils literal notranslate"><span class="pre">frozenset</span></code>, <code class="docutils literal notranslate"><span class="pre">int</span></code>, <code class="docutils literal notranslate"><span class="pre">list</span></code>, <code class="docutils literal notranslate"><span class="pre">set</span></code>, <code class="docutils literal notranslate"><span class="pre">str</span></code>, and <code class="docutils literal notranslate"><span class="pre">tuple</span></code>), a
single positional sub-pattern is allowed to be passed to
the call. Rather than being matched against any particular attribute
on the subject, it is instead matched against the subject itself. This
creates behavior that is useful and intuitive for these objects:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">bool(False)</span></code> matches <code class="docutils literal notranslate"><span class="pre">False</span></code> (but not <code class="docutils literal notranslate"><span class="pre">0</span></code>).</li>
<li><code class="docutils literal notranslate"><span class="pre">tuple((0,</span> <span class="pre">1,</span> <span class="pre">2))</span></code> matches <code class="docutils literal notranslate"><span class="pre">(0,</span> <span class="pre">1,</span> <span class="pre">2)</span></code> (but not <code class="docutils literal notranslate"><span class="pre">[0,</span> <span class="pre">1,</span> <span class="pre">2]</span></code>).</li>
<li><code class="docutils literal notranslate"><span class="pre">int(i)</span></code> matches any <code class="docutils literal notranslate"><span class="pre">int</span></code> and binds it to the name <code class="docutils literal notranslate"><span class="pre">i</span></code>.</li>
</ul>
</section>
<section id="overlapping-sub-patterns">
<h3><a class="toc-backref" href="#overlapping-sub-patterns" role="doc-backlink">Overlapping sub-patterns</a></h3>
<p>Certain classes of overlapping matches are detected at
runtime and will raise exceptions. In addition to basic checks
described in the previous subsection:</p>
<ul class="simple">
<li>The interpreter will check that two match items are not targeting the same
attribute, for example <code class="docutils literal notranslate"><span class="pre">Point2d(1,</span> <span class="pre">2,</span> <span class="pre">y=3)</span></code> is an error.</li>
<li>It will also check that a mapping pattern does not attempt to match
the same key more than once.</li>
</ul>
</section>
<section id="special-attribute-match-args">
<h3><a class="toc-backref" href="#special-attribute-match-args" role="doc-backlink">Special attribute <code class="docutils literal notranslate"><span class="pre">__match_args__</span></code></a></h3>
<p>The <code class="docutils literal notranslate"><span class="pre">__match_args__</span></code> attribute is always looked up on the type
object named in the pattern. If present, it must be a list or tuple
of strings naming the allowed positional arguments.</p>
<p>In deciding what names should be available for matching, the
recommended practice is that class patterns should be the mirror of
construction; that is, the set of available names and their types
should resemble the arguments to <code class="docutils literal notranslate"><span class="pre">__init__()</span></code>.</p>
<p>Only match-by-name will work by default, and classes should define
<code class="docutils literal notranslate"><span class="pre">__match_args__</span></code> as a class attribute if they would like to support
match-by-position. Additionally, dataclasses and named tuples will
support match-by-position out of the box. See below for more details.</p>
</section>
<section id="exceptions-and-side-effects">
<h3><a class="toc-backref" href="#exceptions-and-side-effects" role="doc-backlink">Exceptions and side effects</a></h3>
<p>While matching each case, the <code class="docutils literal notranslate"><span class="pre">match</span></code> statement may trigger execution of other
functions (for example <code class="docutils literal notranslate"><span class="pre">__getitem__()</span></code>, <code class="docutils literal notranslate"><span class="pre">__len__()</span></code> or
a property). Almost every exception caused by those propagates outside of the
match statement normally. The only case where an exception is not propagated is
an <code class="docutils literal notranslate"><span class="pre">AttributeError</span></code> raised while trying to lookup an attribute while matching
attributes of a Class Pattern; that case results in just a matching failure,
and the rest of the statement proceeds normally.</p>
<p>The only side-effect carried on explicitly by the matching process is the binding of
names. However, the process relies on attribute access,
instance checks, <code class="docutils literal notranslate"><span class="pre">len()</span></code>, equality and item access on the subject and some of
its components. It also evaluates constant value patterns and the left side of
class patterns. While none of those typically create any side-effects, some of
these objects could. This proposal intentionally leaves out any specification
of what methods are called or how many times. User code relying on that
behavior should be considered buggy.</p>
</section>
<section id="the-standard-library">
<h3><a class="toc-backref" href="#the-standard-library" role="doc-backlink">The standard library</a></h3>
<p>To facilitate the use of pattern matching, several changes will be made to
the standard library:</p>
<ul class="simple">
<li>Namedtuples and dataclasses will have auto-generated <code class="docutils literal notranslate"><span class="pre">__match_args__</span></code>.</li>
<li>For dataclasses the order of attributes in the generated <code class="docutils literal notranslate"><span class="pre">__match_args__</span></code>
will be the same as the order of corresponding arguments in the generated
<code class="docutils literal notranslate"><span class="pre">__init__()</span></code> method. This includes the situations where attributes are
inherited from a superclass.</li>
</ul>
<p>In addition, a systematic effort will be put into going through
existing standard library classes and adding <code class="docutils literal notranslate"><span class="pre">__match_args__</span></code> where
it looks beneficial.</p>
</section>
</section>
<section id="static-checkers-specification">
<h2><a class="toc-backref" href="#static-checkers-specification" role="doc-backlink">Static checkers specification</a></h2>
<section id="exhaustiveness-checks">
<h3><a class="toc-backref" href="#exhaustiveness-checks" role="doc-backlink">Exhaustiveness checks</a></h3>
<p>From a reliability perspective, experience shows that missing a case when
dealing with a set of possible data values leads to hard to debug issues,
thus forcing people to add safety asserts like this:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">get_first</span><span class="p">(</span><span class="n">data</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">list</span><span class="p">[</span><span class="nb">int</span><span class="p">]])</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="nb">list</span><span class="p">)</span> <span class="ow">and</span> <span class="n">data</span><span class="p">:</span>
<span class="k">return</span> <span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="nb">int</span><span class="p">):</span>
<span class="k">return</span> <span class="n">data</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">assert</span> <span class="kc">False</span><span class="p">,</span> <span class="s2">&quot;should never get here&quot;</span>
</pre></div>
</div>
<p><a class="pep reference internal" href="../pep-0484/" title="PEP 484 Type Hints">PEP 484</a> specifies that static type checkers should support exhaustiveness in
conditional checks with respect to enum values. <a class="pep reference internal" href="../pep-0586/" title="PEP 586 Literal Types">PEP 586</a> later generalized this
requirement to literal types.</p>
<p>This PEP further generalizes this requirement to
arbitrary patterns. A typical situation where this applies is matching an
expression with a union type:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">classify</span><span class="p">(</span><span class="n">val</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="n">Tuple</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">int</span><span class="p">],</span> <span class="n">List</span><span class="p">[</span><span class="nb">int</span><span class="p">]])</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">match</span> <span class="n">val</span><span class="p">:</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="k">if</span> <span class="n">x</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">y</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;A pair of </span><span class="si">{</span><span class="n">x</span><span class="si">}</span><span class="s2"> and </span><span class="si">{</span><span class="n">y</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="k">case</span> <span class="p">[</span><span class="n">x</span><span class="p">,</span> <span class="o">*</span><span class="n">other</span><span class="p">]:</span>
<span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;A sequence starting with </span><span class="si">{</span><span class="n">x</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="k">case</span> <span class="nb">int</span><span class="p">():</span>
<span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;Some integer&quot;</span>
<span class="c1"># Type-checking error: some cases unhandled.</span>
</pre></div>
</div>
<p>The exhaustiveness checks should also apply where both pattern matching
and enum values are combined:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">enum</span> <span class="kn">import</span> <span class="n">Enum</span>
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Union</span>
<span class="k">class</span> <span class="nc">Level</span><span class="p">(</span><span class="n">Enum</span><span class="p">):</span>
<span class="n">BASIC</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">ADVANCED</span> <span class="o">=</span> <span class="mi">2</span>
<span class="n">PRO</span> <span class="o">=</span> <span class="mi">3</span>
<span class="k">class</span> <span class="nc">User</span><span class="p">:</span>
<span class="n">name</span><span class="p">:</span> <span class="nb">str</span>
<span class="n">level</span><span class="p">:</span> <span class="n">Level</span>
<span class="k">class</span> <span class="nc">Admin</span><span class="p">:</span>
<span class="n">name</span><span class="p">:</span> <span class="nb">str</span>
<span class="n">account</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="n">User</span><span class="p">,</span> <span class="n">Admin</span><span class="p">]</span>
<span class="k">match</span> <span class="n">account</span><span class="p">:</span>
<span class="k">case</span> <span class="n">Admin</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="n">name</span><span class="p">)</span> <span class="o">|</span> <span class="n">User</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="n">name</span><span class="p">,</span> <span class="n">level</span><span class="o">=</span><span class="n">Level</span><span class="o">.</span><span class="n">PRO</span><span class="p">):</span>
<span class="o">...</span>
<span class="k">case</span> <span class="n">User</span><span class="p">(</span><span class="n">level</span><span class="o">=</span><span class="n">Level</span><span class="o">.</span><span class="n">ADVANCED</span><span class="p">):</span>
<span class="o">...</span>
<span class="c1"># Type-checking error: basic user unhandled</span>
</pre></div>
</div>
<p>Obviously, no <code class="docutils literal notranslate"><span class="pre">Matchable</span></code> protocol (in terms of <a class="pep reference internal" href="../pep-0544/" title="PEP 544 Protocols: Structural subtyping (static duck typing)">PEP 544</a>) is needed, since
every class is matchable and therefore is subject to the checks specified
above.</p>
</section>
<section id="sealed-classes-as-algebraic-data-types">
<h3><a class="toc-backref" href="#sealed-classes-as-algebraic-data-types" role="doc-backlink">Sealed classes as algebraic data types</a></h3>
<p>Quite often it is desirable to apply exhaustiveness to a set of classes without
defining ad-hoc union types, which is itself fragile if a class is missing in
the union definition. A design pattern where a group of record-like classes is
combined into a union is popular in other languages that support pattern
matching and is known under a name of <a class="reference external" href="https://en.wikipedia.org/wiki/Algebraic_data_type">algebraic data types</a>.</p>
<p>We propose to add a special decorator class <code class="docutils literal notranslate"><span class="pre">&#64;sealed</span></code> to the <a class="reference external" href="https://docs.python.org/3/library/typing.html#module-typing" title="(in Python v3.12)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">typing</span></code></a>
module, that will have no effect at runtime, but will indicate to static
type checkers that all subclasses (direct and indirect) of this class should
be defined in the same module as the base class.</p>
<p>The idea is that since all subclasses are known, the type checker can treat
the sealed base class as a union of all its subclasses. Together with
dataclasses this allows a clean and safe support of algebraic data types
in Python. Consider this example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">dataclasses</span> <span class="kn">import</span> <span class="n">dataclass</span>
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">sealed</span>
<span class="nd">@sealed</span>
<span class="k">class</span> <span class="nc">Node</span><span class="p">:</span>
<span class="o">...</span>
<span class="k">class</span> <span class="nc">Expression</span><span class="p">(</span><span class="n">Node</span><span class="p">):</span>
<span class="o">...</span>
<span class="k">class</span> <span class="nc">Statement</span><span class="p">(</span><span class="n">Node</span><span class="p">):</span>
<span class="o">...</span>
<span class="nd">@dataclass</span>
<span class="k">class</span> <span class="nc">Name</span><span class="p">(</span><span class="n">Expression</span><span class="p">):</span>
<span class="n">name</span><span class="p">:</span> <span class="nb">str</span>
<span class="nd">@dataclass</span>
<span class="k">class</span> <span class="nc">Operation</span><span class="p">(</span><span class="n">Expression</span><span class="p">):</span>
<span class="n">left</span><span class="p">:</span> <span class="n">Expression</span>
<span class="n">op</span><span class="p">:</span> <span class="nb">str</span>
<span class="n">right</span><span class="p">:</span> <span class="n">Expression</span>
<span class="nd">@dataclass</span>
<span class="k">class</span> <span class="nc">Assignment</span><span class="p">(</span><span class="n">Statement</span><span class="p">):</span>
<span class="n">target</span><span class="p">:</span> <span class="nb">str</span>
<span class="n">value</span><span class="p">:</span> <span class="n">Expression</span>
<span class="nd">@dataclass</span>
<span class="k">class</span> <span class="nc">Print</span><span class="p">(</span><span class="n">Statement</span><span class="p">):</span>
<span class="n">value</span><span class="p">:</span> <span class="n">Expression</span>
</pre></div>
</div>
<p>With such definition, a type checker can safely treat <code class="docutils literal notranslate"><span class="pre">Node</span></code> as
<code class="docutils literal notranslate"><span class="pre">Union[Name,</span> <span class="pre">Operation,</span> <span class="pre">Assignment,</span> <span class="pre">Print]</span></code>, and also safely treat e.g.
<code class="docutils literal notranslate"><span class="pre">Expression</span></code> as <code class="docutils literal notranslate"><span class="pre">Union[Name,</span> <span class="pre">Operation]</span></code>. So this will result in a type
checking error in the below snippet, because <code class="docutils literal notranslate"><span class="pre">Name</span></code> is not handled (and type
checker can give a useful error message):</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">dump</span><span class="p">(</span><span class="n">node</span><span class="p">:</span> <span class="n">Node</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">match</span> <span class="n">node</span><span class="p">:</span>
<span class="k">case</span> <span class="n">Assignment</span><span class="p">(</span><span class="n">target</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
<span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">target</span><span class="si">}</span><span class="s2"> = </span><span class="si">{</span><span class="n">dump</span><span class="p">(</span><span class="n">value</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="k">case</span> <span class="n">Print</span><span class="p">(</span><span class="n">value</span><span class="p">):</span>
<span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;print(</span><span class="si">{</span><span class="n">dump</span><span class="p">(</span><span class="n">value</span><span class="p">)</span><span class="si">}</span><span class="s2">)&quot;</span>
<span class="k">case</span> <span class="n">Operation</span><span class="p">(</span><span class="n">left</span><span class="p">,</span> <span class="n">op</span><span class="p">,</span> <span class="n">right</span><span class="p">):</span>
<span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;(</span><span class="si">{</span><span class="n">dump</span><span class="p">(</span><span class="n">left</span><span class="p">)</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="n">op</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="n">dump</span><span class="p">(</span><span class="n">right</span><span class="p">)</span><span class="si">}</span><span class="s2">)&quot;</span>
</pre></div>
</div>
</section>
<section id="type-erasure">
<h3><a class="toc-backref" href="#type-erasure" role="doc-backlink">Type erasure</a></h3>
<p>Class patterns are subject to runtime type erasure. Namely, although one
can define a type alias <code class="docutils literal notranslate"><span class="pre">IntQueue</span> <span class="pre">=</span> <span class="pre">Queue[int]</span></code> so that a pattern like
<code class="docutils literal notranslate"><span class="pre">IntQueue()</span></code> is syntactically valid, type checkers should reject such a
match:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">queue</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="n">Queue</span><span class="p">[</span><span class="nb">int</span><span class="p">],</span> <span class="n">Queue</span><span class="p">[</span><span class="nb">str</span><span class="p">]]</span>
<span class="k">match</span> <span class="n">queue</span><span class="p">:</span>
<span class="k">case</span> <span class="n">IntQueue</span><span class="p">():</span> <span class="c1"># Type-checking error here</span>
<span class="o">...</span>
</pre></div>
</div>
<p>Note that the above snippet actually fails at runtime with the current
implementation of generic classes in the <code class="docutils literal notranslate"><span class="pre">typing</span></code> module, as well as
with builtin generic classes in the recently accepted <a class="pep reference internal" href="../pep-0585/" title="PEP 585 Type Hinting Generics In Standard Collections">PEP 585</a>, because
they prohibit <code class="docutils literal notranslate"><span class="pre">isinstance</span></code> checks.</p>
<p>To clarify, generic classes are not prohibited in general from participating
in pattern matching, just that their type parameters cant be explicitly
specified. It is still fine if sub-patterns or literals bind the type
variables. For example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Generic</span><span class="p">,</span> <span class="n">TypeVar</span><span class="p">,</span> <span class="n">Union</span>
<span class="n">T</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s1">&#39;T&#39;</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Result</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">T</span><span class="p">]):</span>
<span class="n">first</span><span class="p">:</span> <span class="n">T</span>
<span class="n">other</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="n">T</span><span class="p">]</span>
<span class="n">result</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="n">Result</span><span class="p">[</span><span class="nb">int</span><span class="p">],</span> <span class="n">Result</span><span class="p">[</span><span class="nb">str</span><span class="p">]]</span>
<span class="k">match</span> <span class="n">result</span><span class="p">:</span>
<span class="k">case</span> <span class="n">Result</span><span class="p">(</span><span class="n">first</span><span class="o">=</span><span class="nb">int</span><span class="p">()):</span>
<span class="o">...</span> <span class="c1"># Type of result is Result[int] here</span>
<span class="k">case</span> <span class="n">Result</span><span class="p">(</span><span class="n">other</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;foo&quot;</span><span class="p">,</span> <span class="s2">&quot;bar&quot;</span><span class="p">,</span> <span class="o">*</span><span class="n">rest</span><span class="p">]):</span>
<span class="o">...</span> <span class="c1"># Type of result is Result[str] here</span>
</pre></div>
</div>
</section>
<section id="note-about-constants">
<h3><a class="toc-backref" href="#note-about-constants" role="doc-backlink">Note about constants</a></h3>
<p>The fact that a capture pattern is always an assignment target may create unwanted
consequences when a user by mistake tries to “match” a value against
a constant instead of using the constant value pattern. As a result, at
runtime such a match will always succeed and moreover override the value of
the constant. It is important therefore that static type checkers warn about
such situations. For example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Final</span>
<span class="n">MAX_INT</span><span class="p">:</span> <span class="n">Final</span> <span class="o">=</span> <span class="mi">2</span> <span class="o">**</span> <span class="mi">64</span>
<span class="n">value</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">match</span> <span class="n">value</span><span class="p">:</span>
<span class="k">case</span> <span class="n">MAX_INT</span><span class="p">:</span> <span class="c1"># Type-checking error here: cannot assign to final name</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Got big number&quot;</span><span class="p">)</span>
<span class="k">case</span><span class="w"> </span><span class="k">_</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Something else&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>Note that the CPython reference implementation also generates a
<code class="docutils literal notranslate"><span class="pre">SyntaxWarning</span></code> message for this case.</p>
</section>
<section id="precise-type-checking-of-star-matches">
<h3><a class="toc-backref" href="#precise-type-checking-of-star-matches" role="doc-backlink">Precise type checking of star matches</a></h3>
<p>Type checkers should perform precise type checking of star items in pattern
matching giving them either a heterogeneous <code class="docutils literal notranslate"><span class="pre">list[T]</span></code> type, or
a <code class="docutils literal notranslate"><span class="pre">TypedDict</span></code> type as specified by <a class="pep reference internal" href="../pep-0589/" title="PEP 589 TypedDict: Type Hints for Dictionaries with a Fixed Set of Keys">PEP 589</a>. For example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">stuff</span><span class="p">:</span> <span class="n">Tuple</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">,</span> <span class="nb">float</span><span class="p">]</span>
<span class="k">match</span> <span class="n">stuff</span><span class="p">:</span>
<span class="k">case</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="mf">0.5</span><span class="p">:</span>
<span class="c1"># Here a is int and b is list[str]</span>
<span class="o">...</span>
</pre></div>
</div>
</section>
</section>
<section id="performance-considerations">
<h2><a class="toc-backref" href="#performance-considerations" role="doc-backlink">Performance Considerations</a></h2>
<p>Ideally, a <code class="docutils literal notranslate"><span class="pre">match</span></code> statement should have good runtime performance compared
to an equivalent chain of if-statements. Although the history of programming
languages is rife with examples of new features which increased engineer
productivity at the expense of additional CPU cycles, it would be
unfortunate if the benefits of <code class="docutils literal notranslate"><span class="pre">match</span></code> were counter-balanced by a significant
overall decrease in runtime performance.</p>
<p>Although this PEP does not specify any particular implementation strategy,
a few words about the prototype implementation and how it attempts to
maximize performance are in order.</p>
<p>Basically, the prototype implementation transforms all of the <code class="docutils literal notranslate"><span class="pre">match</span></code>
statement syntax into equivalent if/else blocks - or more accurately, into
Python byte codes that have the same effect. In other words, all of the
logic for testing instance types, sequence lengths, mapping keys and
so on are inlined in place of the <code class="docutils literal notranslate"><span class="pre">match</span></code>.</p>
<p>This is not the only possible strategy, nor is it necessarily the best.
For example, the instance checks could be memoized, especially
if there are multiple instances of the same class type but with different
arguments in a single match statement. It is also theoretically
possible for a future implementation to process case clauses or sub-patterns in
parallel using a decision tree rather than testing them one by one.</p>
</section>
<section id="backwards-compatibility">
<h2><a class="toc-backref" href="#backwards-compatibility" role="doc-backlink">Backwards Compatibility</a></h2>
<p>This PEP is fully backwards compatible: the <code class="docutils literal notranslate"><span class="pre">match</span></code> and <code class="docutils literal notranslate"><span class="pre">case</span></code>
keywords are proposed to be (and stay!) soft keywords, so their use as
variable, function, class, module or attribute names is not impeded at
all.</p>
<p>This is important because <code class="docutils literal notranslate"><span class="pre">match</span></code> is the name of a popular and
well-known function and method in the <code class="docutils literal notranslate"><span class="pre">re</span></code> module, which we have no
desire to break or deprecate.</p>
<p>The difference between hard and soft keywords is that hard keywords
are <em>always</em> reserved words, even in positions where they make no
sense (e.g. <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">=</span> <span class="pre">class</span> <span class="pre">+</span> <span class="pre">1</span></code>), while soft keywords only get a special
meaning in context. Since <a class="pep reference internal" href="../pep-0617/" title="PEP 617 New PEG parser for CPython">PEP 617</a> the parser backtracks, that means that on
different attempts to parse a code fragment it could interpret a soft
keyword differently.</p>
<p>For example, suppose the parser encounters the following input:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</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>The parser first attempts to parse this as an expression statement.
It interprets <code class="docutils literal notranslate"><span class="pre">match</span></code> as a NAME token, and then considers <code class="docutils literal notranslate"><span class="pre">[x,</span>
<span class="pre">y]</span></code> to be a double subscript. It then encounters the colon and has
to backtrack, since an expression statement cannot be followed by a
colon. The parser then backtracks to the start of the line and finds
that <code class="docutils literal notranslate"><span class="pre">match</span></code> is a soft keyword allowed in this position. It then
considers <code class="docutils literal notranslate"><span class="pre">[x,</span> <span class="pre">y]</span></code> to be a list expression. The colon then is just
what the parser expected, and the parse succeeds.</p>
</section>
<section id="impacts-on-third-party-tools">
<h2><a class="toc-backref" href="#impacts-on-third-party-tools" role="doc-backlink">Impacts on third-party tools</a></h2>
<p>There are a lot of tools in the Python ecosystem that operate on Python
source code: linters, syntax highlighters, auto-formatters, and IDEs. These
will all need to be updated to include awareness of the <code class="docutils literal notranslate"><span class="pre">match</span></code> statement.</p>
<p>In general, these tools fall into one of two categories:</p>
<p><strong>Shallow</strong> parsers dont try to understand the full syntax of Python, but
instead scan the source code for specific known patterns. IDEs, such as Visual
Studio Code, Emacs and TextMate, tend to fall in this category, since frequently
the source code is invalid while being edited, and a strict approach to parsing
would fail.</p>
<p>For these kinds of tools, adding knowledge of a new keyword is relatively
easy, just an addition to a table, or perhaps modification of a regular
expression.</p>
<p><strong>Deep</strong> parsers understand the complete syntax of Python. An example of this
is the auto-formatter <a class="reference external" href="https://black.readthedocs.io/en/stable/">Black</a>. A particular requirement with these kinds of
tools is that they not only need to understand the syntax of the current version
of Python, but older versions of Python as well.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">match</span></code> statement uses a soft keyword, and it is one of the first major
Python features to take advantage of the capabilities of the new PEG parser. This
means that third-party parsers which are not PEG-compatible will have a hard
time with the new syntax.</p>
<p>It has been noted that a number of these third-party tools leverage common parsing
libraries (Black for example uses a fork of the lib2to3 parser). It may be helpful
to identify widely used parsing libraries (such as <a class="reference external" href="https://github.com/davidhalter/parso">parso</a> and <a class="reference external" href="https://github.com/Instagram/LibCST">libCST</a>)
and upgrade them to be PEG compatible.</p>
<p>However, since this work would need to be done not only for the match statement,
but for <em>any</em> new Python syntax that leverages the capabilities of the PEG parser,
it is considered out of scope for this PEP. (Although it is suggested that this
would make a fine Summer of Code project.)</p>
</section>
<section id="reference-implementation">
<h2><a class="toc-backref" href="#reference-implementation" role="doc-backlink">Reference Implementation</a></h2>
<p>A <a class="reference external" href="https://github.com/brandtbucher/cpython/tree/patma">feature-complete CPython implementation</a> is available on
GitHub.</p>
<p>An <a class="reference external" href="https://mybinder.org/v2/gh/gvanrossum/patma/master?urlpath=lab/tree/playground-622.ipynb">interactive playground</a>
based on the above implementation was created using <a class="reference external" href="https://mybinder.org">Binder</a> and <a class="reference external" href="https://jupyter.org">Jupyter</a>.</p>
</section>
<section id="example-code">
<h2><a class="toc-backref" href="#example-code" role="doc-backlink">Example Code</a></h2>
<p>A small <a class="reference external" href="https://github.com/gvanrossum/patma/tree/master/examples">collection of example code</a> is
available on GitHub.</p>
</section>
<section id="rejected-ideas">
<h2><a class="toc-backref" href="#rejected-ideas" role="doc-backlink">Rejected Ideas</a></h2>
<p>This general idea has been floating around for a pretty long time, and many
back and forth decisions were made. Here we summarize many alternative
paths that were taken but eventually abandoned.</p>
<section id="don-t-do-this-pattern-matching-is-hard-to-learn">
<h3><a class="toc-backref" href="#don-t-do-this-pattern-matching-is-hard-to-learn" role="doc-backlink">Dont do this, pattern matching is hard to learn</a></h3>
<p>In our opinion, the proposed pattern matching is not more difficult than
adding <code class="docutils literal notranslate"><span class="pre">isinstance()</span></code> and <code class="docutils literal notranslate"><span class="pre">getattr()</span></code> to iterable unpacking. Also, we
believe the proposed syntax significantly improves readability for a wide
range of code patterns, by allowing to express <em>what</em> one wants to do, rather
than <em>how</em> to do it. We hope the few real code snippets we included in the PEP
above illustrate this comparison well enough. For more real code examples
and their translations see Ref. <a class="footnote-reference brackets" href="#id3" id="id2">[1]</a>.</p>
</section>
<section id="don-t-do-this-use-existing-method-dispatching-mechanisms">
<h3><a class="toc-backref" href="#don-t-do-this-use-existing-method-dispatching-mechanisms" role="doc-backlink">Dont do this, use existing method dispatching mechanisms</a></h3>
<p>We recognize that some of the use cases for the <code class="docutils literal notranslate"><span class="pre">match</span></code> statement overlap
with what can be done with traditional object-oriented programming (OOP) design
techniques using class inheritance. The ability to choose alternate
behaviors based on testing the runtime type of a match subject might
even seem heretical to strict OOP purists.</p>
<p>However, Python has always been a language that embraces a variety of
programming styles and paradigms. Classic Python design idioms such as
“duck”-typing go beyond the traditional OOP model.</p>
<p>We believe that there are important use cases where the use of <code class="docutils literal notranslate"><span class="pre">match</span></code> results
in a cleaner and more maintainable architecture. These use cases tend to
be characterized by a number of features:</p>
<ul class="simple">
<li>Algorithms which cut across traditional lines of data encapsulation. If an
algorithm is processing heterogeneous elements of different types (such as
evaluating or transforming an abstract syntax tree, or doing algebraic
manipulation of mathematical symbols), forcing the user to implement
the algorithm as individual methods on each element type results in
logic that is smeared across the entire codebase instead of being neatly
localized in one place.</li>
<li>Program architectures where the set of possible data types is relatively
stable, but there is an ever-expanding set of operations to be performed
on those data types. Doing this in a strict OOP fashion requires constantly
adding new methods to both the base class and subclasses to support the new
methods, “polluting” the base class with lots of very specialized method
definitions, and causing widespread disruption and churn in the code. By
contrast, in a <code class="docutils literal notranslate"><span class="pre">match</span></code>-based dispatch, adding a new behavior merely
involves writing a new <code class="docutils literal notranslate"><span class="pre">match</span></code> statement.</li>
<li>OOP also does not handle dispatching based on the <em>shape</em> of an object, such
as the length of a tuple, or the presence of an attribute instead any such
dispatching decision must be encoded into the objects type. Shape-based
dispatching is particularly interesting when it comes to handling “duck”-typed
objects.</li>
</ul>
<p>Where OOP is clearly superior is in the opposite case: where the set of possible
operations is relatively stable and well-defined, but there is an ever-growing
set of data types to operate on. A classic example of this is UI widget toolkits,
where there is a fixed set of interaction types (repaint, mouse click, keypress,
and so on), but the set of widget types is constantly expanding as developers
invent new and creative user interaction styles. Adding a new kind of widget
is a simple matter of writing a new subclass, whereas with a match-based approach
you end up having to add a new case clause to many widespread match statements.
We therefore dont recommend using <code class="docutils literal notranslate"><span class="pre">match</span></code> in such a situation.</p>
</section>
<section id="allow-more-flexible-assignment-targets-instead">
<h3><a class="toc-backref" href="#allow-more-flexible-assignment-targets-instead" role="doc-backlink">Allow more flexible assignment targets instead</a></h3>
<p>There was an idea to instead just generalize the iterable unpacking to much
more general assignment targets, instead of adding a new kind of statement.
This concept is known in some other languages as “irrefutable matches”. We
decided not to do this because inspection of real-life potential use cases
showed that in vast majority of cases destructuring is related to an <code class="docutils literal notranslate"><span class="pre">if</span></code>
condition. Also many of those are grouped in a series of exclusive choices.</p>
</section>
<section id="make-it-an-expression">
<h3><a class="toc-backref" href="#make-it-an-expression" role="doc-backlink">Make it an expression</a></h3>
<p>In most other languages pattern matching is represented by an expression, not
statement. But making it an expression would be inconsistent with other
syntactic choices in Python. All decision making logic is expressed almost
exclusively in statements, so we decided to not deviate from this.</p>
</section>
<section id="use-a-hard-keyword">
<h3><a class="toc-backref" href="#use-a-hard-keyword" role="doc-backlink">Use a hard keyword</a></h3>
<p>There were options to make <code class="docutils literal notranslate"><span class="pre">match</span></code> a hard keyword, or choose a different
keyword. Although using a hard keyword would simplify life for simple-minded
syntax highlighters, we decided not to use hard keyword for several reasons:</p>
<ul class="simple">
<li>Most importantly, the new parser doesnt require us to do this. Unlike with
<code class="docutils literal notranslate"><span class="pre">async</span></code> that caused hardships with being a soft keyword for few releases,
here we can make <code class="docutils literal notranslate"><span class="pre">match</span></code> a permanent soft keyword.</li>
<li><code class="docutils literal notranslate"><span class="pre">match</span></code> is so commonly used in existing code, that it would break almost
every existing program and will put a burden to fix code on many people who
may not even benefit from the new syntax.</li>
<li>It is hard to find an alternative keyword that would not be commonly used
in existing programs as an identifier, and would still clearly reflect the
meaning of the statement.</li>
</ul>
</section>
<section id="use-as-or-instead-of-case-for-case-clauses">
<h3><a class="toc-backref" href="#use-as-or-instead-of-case-for-case-clauses" role="doc-backlink">Use <code class="docutils literal notranslate"><span class="pre">as</span></code> or <code class="docutils literal notranslate"><span class="pre">|</span></code> instead of <code class="docutils literal notranslate"><span class="pre">case</span></code> for case clauses</a></h3>
<p>The pattern matching proposed here is a combination of multi-branch control
flow (in line with <code class="docutils literal notranslate"><span class="pre">switch</span></code> in Algol-derived languages or <code class="docutils literal notranslate"><span class="pre">cond</span></code> in Lisp)
and object-deconstruction as found in functional languages. While the proposed
keyword <code class="docutils literal notranslate"><span class="pre">case</span></code> highlights the multi-branch aspect, alternative keywords such
as <code class="docutils literal notranslate"><span class="pre">as</span></code> would equally be possible, highlighting the deconstruction aspect.
<code class="docutils literal notranslate"><span class="pre">as</span></code> or <code class="docutils literal notranslate"><span class="pre">with</span></code>, for instance, also have the advantage of already being
keywords in Python. However, since <code class="docutils literal notranslate"><span class="pre">case</span></code> as a keyword can only occur as a
leading keyword inside a <code class="docutils literal notranslate"><span class="pre">match</span></code> statement, it is easy for a parser to
distinguish between its use as a keyword or as a variable.</p>
<p>Other variants would use a symbol like <code class="docutils literal notranslate"><span class="pre">|</span></code> or <code class="docutils literal notranslate"><span class="pre">=&gt;</span></code>, or go entirely without
special marker.</p>
<p>Since Python is a statement-oriented language in the tradition of Algol, and as
each composite statement starts with an identifying keyword, <code class="docutils literal notranslate"><span class="pre">case</span></code> seemed to
be most in line with Pythons style and traditions.</p>
</section>
<section id="use-a-flat-indentation-scheme">
<h3><a class="toc-backref" href="#use-a-flat-indentation-scheme" role="doc-backlink">Use a flat indentation scheme</a></h3>
<p>There was an idea to use an alternative indentation scheme, for example where
every case clause would not be indented with respect to the initial <code class="docutils literal notranslate"><span class="pre">match</span></code>
part:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">expression</span><span class="p">:</span>
<span class="k">case</span> <span class="n">pattern_1</span><span class="p">:</span>
<span class="o">...</span>
<span class="k">case</span> <span class="n">pattern_2</span><span class="p">:</span>
<span class="o">...</span>
</pre></div>
</div>
<p>The motivation is that although flat indentation saves some horizontal space,
it may look awkward to an eye of a Python programmer, because everywhere else
colon is followed by an indent. This will also complicate life for
simple-minded code editors. Finally, the horizontal space issue can be
alleviated by allowing “half-indent” (i.e. two spaces instead of four) for
match statements.</p>
<p>In sample programs using <code class="docutils literal notranslate"><span class="pre">match</span></code>, written as part of the development of this
PEP, a noticeable improvement in code brevity is observed, more than making up
for the additional indentation level.</p>
<p>Another proposal considered was to use flat indentation but put the
expression on the line after <code class="docutils literal notranslate"><span class="pre">match:</span></code>, like this:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">match</span><span class="p">:</span>
<span class="n">expression</span>
<span class="k">case</span> <span class="n">pattern_1</span><span class="p">:</span>
<span class="o">...</span>
<span class="k">case</span> <span class="n">pattern_2</span><span class="p">:</span>
<span class="o">...</span>
</pre></div>
</div>
<p>This was ultimately rejected because the first block would be a
novelty in Pythons grammar: a block whose only content is a single
expression rather than a sequence of statements.</p>
</section>
<section id="alternatives-for-constant-value-pattern">
<h3><a class="toc-backref" href="#alternatives-for-constant-value-pattern" role="doc-backlink">Alternatives for constant value pattern</a></h3>
<p>This is probably the trickiest item. Matching against some pre-defined
constants is very common, but the dynamic nature of Python also makes it
ambiguous with capture patterns. Five other alternatives were considered:</p>
<ul>
<li>Use some implicit rules. For example, if a name was defined in the global
scope, then it refers to a constant, rather than representing a
capture pattern:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Here, the name &quot;spam&quot; must be defined in the global scope (and</span>
<span class="c1"># not shadowed locally). &quot;side&quot; must be local.</span>
<span class="k">match</span> <span class="n">entree</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]:</span>
<span class="k">case</span> <span class="n">spam</span><span class="p">:</span> <span class="o">...</span> <span class="c1"># Compares entree[-1] == spam.</span>
<span class="k">case</span> <span class="n">side</span><span class="p">:</span> <span class="o">...</span> <span class="c1"># Assigns side = entree[-1].</span>
</pre></div>
</div>
<p>This however can cause surprises and action at a distance if someone
defines an unrelated coinciding name before the match statement.</p>
</li>
<li>Use a rule based on the case of a name. In particular, if the name
starts with a lowercase letter it would be a capture pattern, while if
it starts with uppercase it would refer to a constant:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">entree</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]:</span>
<span class="k">case</span> <span class="n">SPAM</span><span class="p">:</span> <span class="o">...</span> <span class="c1"># Compares entree[-1] == SPAM.</span>
<span class="k">case</span> <span class="n">side</span><span class="p">:</span> <span class="o">...</span> <span class="c1"># Assigns side = entree[-1].</span>
</pre></div>
</div>
<p>This works well with the recommendations for naming constants from
<a class="pep reference internal" href="../pep-0008/" title="PEP 8 Style Guide for Python Code">PEP 8</a>. The main objection is that theres no other part of core
Python where the case of a name is semantically significant.
In addition, Python allows identifiers to use different scripts,
many of which (e.g. CJK) dont have a case distinction.</p>
</li>
<li>Use extra parentheses to indicate lookup semantics for a given name. For
example:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">entree</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]:</span>
<span class="k">case</span> <span class="p">(</span><span class="n">spam</span><span class="p">):</span> <span class="o">...</span> <span class="c1"># Compares entree[-1] == spam.</span>
<span class="k">case</span> <span class="n">side</span><span class="p">:</span> <span class="o">...</span> <span class="c1"># Assigns side = entree[-1].</span>
</pre></div>
</div>
<p>This may be a viable option, but it can create some visual noise if used
often. Also honestly it looks pretty unusual, especially in nested contexts.</p>
<p>This also has the problem that we may want or need parentheses to
disambiguate grouping in patterns, e.g. in <code class="docutils literal notranslate"><span class="pre">Point(x,</span> <span class="pre">y=(y</span> <span class="pre">:=</span>
<span class="pre">complex()))</span></code>.</p>
</li>
<li>Introduce a special symbol, for example <code class="docutils literal notranslate"><span class="pre">.</span></code>, <code class="docutils literal notranslate"><span class="pre">?</span></code>, <code class="docutils literal notranslate"><span class="pre">$</span></code>, or <code class="docutils literal notranslate"><span class="pre">^</span></code> to
indicate that a given name is a value to be matched against, not
to be assigned to. An earlier version of this proposal used a
leading-dot rule:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">entree</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]:</span>
<span class="k">case</span> <span class="o">.</span><span class="n">spam</span><span class="p">:</span> <span class="o">...</span> <span class="c1"># Compares entree[-1] == spam.</span>
<span class="k">case</span> <span class="n">side</span><span class="p">:</span> <span class="o">...</span> <span class="c1"># Assigns side = entree[-1].</span>
</pre></div>
</div>
<p>While potentially useful, it introduces strange-looking new syntax
without making the pattern syntax any more expressive. Indeed,
named constants can be made to work with the existing rules by
converting them to <code class="docutils literal notranslate"><span class="pre">Enum</span></code> types, or enclosing them in their own
namespace (considered by the authors to be one honking great idea):</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">entree</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]:</span>
<span class="k">case</span> <span class="n">Sides</span><span class="o">.</span><span class="n">SPAM</span><span class="p">:</span> <span class="o">...</span> <span class="c1"># Compares entree[-1] == Sides.SPAM.</span>
<span class="k">case</span> <span class="n">side</span><span class="p">:</span> <span class="o">...</span> <span class="c1"># Assigns side = entree[-1].</span>
</pre></div>
</div>
<p>If needed, the leading-dot rule (or a similar variant) could be
added back later with no backward-compatibility issues.</p>
</li>
<li>There was also an idea to make lookup semantics the default, and require
<code class="docutils literal notranslate"><span class="pre">$</span></code> or <code class="docutils literal notranslate"><span class="pre">?</span></code> to be used in capture patterns:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>match entree[-1]:
case spam: ... # Compares entree[-1] == spam.
case side?: ... # Assigns side = entree[-1].
</pre></div>
</div>
<p>There are a few issues with this:</p>
<ul>
<li>Capture patterns are more common in typical code, so it is
undesirable to require special syntax for them.</li>
<li>The authors are not aware of any other language that adorns
captures in this way.</li>
<li>None of the proposed syntaxes have any precedent in Python;
no other place in Python that binds names (e.g. <code class="docutils literal notranslate"><span class="pre">import</span></code>,
<code class="docutils literal notranslate"><span class="pre">def</span></code>, <code class="docutils literal notranslate"><span class="pre">for</span></code>) uses special marker syntax.</li>
<li>It would break the syntactic parallels of the current grammar:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>match coords:
case ($x, $y):
return Point(x, y) # Why not &quot;Point($x, $y)&quot;?
</pre></div>
</div>
</li>
</ul>
</li>
</ul>
<p>In the end, these alternatives were rejected because of the mentioned drawbacks.</p>
</section>
<section id="disallow-float-literals-in-patterns">
<h3><a class="toc-backref" href="#disallow-float-literals-in-patterns" role="doc-backlink">Disallow float literals in patterns</a></h3>
<p>Because of the inexactness of floats, an early version of this proposal
did not allow floating-point constants to be used as match patterns. Part
of the justification for this prohibition is that Rust does this.</p>
<p>However, during implementation, it was discovered that distinguishing between
float values and other types required extra code in the VM that would slow
matches generally. Given that Python and Rust are very different languages
with different user bases and underlying philosophies, it was felt that
allowing float literals would not cause too much harm, and would be less
surprising to users.</p>
</section>
<section id="range-matching-patterns">
<h3><a class="toc-backref" href="#range-matching-patterns" role="doc-backlink">Range matching patterns</a></h3>
<p>This would allow patterns such as <code class="docutils literal notranslate"><span class="pre">1...6</span></code>. However, there are a host of
ambiguities:</p>
<ul class="simple">
<li>Is the range open, half-open, or closed? (I.e. is <code class="docutils literal notranslate"><span class="pre">6</span></code> included in the
above example or not?)</li>
<li>Does the range match a single number, or a range object?</li>
<li>Range matching is often used for character ranges (az) but that
wont work in Python since theres no character data type, just strings.</li>
<li>Range matching can be a significant performance optimization if you can
pre-build a jump table, but thats not generally possible in Python due
to the fact that names can be dynamically rebound.</li>
</ul>
<p>Rather than creating a special-case syntax for ranges, it was decided
that allowing custom pattern objects (<code class="docutils literal notranslate"><span class="pre">InRange(0,</span> <span class="pre">6)</span></code>) would be more flexible
and less ambiguous; however those ideas have been postponed for the time
being (See <a class="reference internal" href="#deferred-ideas">deferred ideas</a>).</p>
</section>
<section id="use-dispatch-dict-semantics-for-matches">
<h3><a class="toc-backref" href="#use-dispatch-dict-semantics-for-matches" role="doc-backlink">Use dispatch dict semantics for matches</a></h3>
<p>Implementations for classic <code class="docutils literal notranslate"><span class="pre">switch</span></code> statement sometimes use a pre-computed
hash table instead of a chained equality comparisons to gain some performance.
In the context of <code class="docutils literal notranslate"><span class="pre">match</span></code> statement this is technically also possible for
matches against literal patterns. However, having subtly different semantics
for different kinds of patterns would be too surprising for potentially
modest performance win.</p>
<p>We can still experiment with possible performance optimizations in this
direction if they will not cause semantic differences.</p>
</section>
<section id="use-continue-and-break-in-case-clauses">
<h3><a class="toc-backref" href="#use-continue-and-break-in-case-clauses" role="doc-backlink">Use <code class="docutils literal notranslate"><span class="pre">continue</span></code> and <code class="docutils literal notranslate"><span class="pre">break</span></code> in case clauses.</a></h3>
<p>Another rejected proposal was to define new meanings for <code class="docutils literal notranslate"><span class="pre">continue</span></code>
and <code class="docutils literal notranslate"><span class="pre">break</span></code> inside of <code class="docutils literal notranslate"><span class="pre">match</span></code>, which would have the following behavior:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">continue</span></code> would exit the current case clause and continue matching
at the next case clause.</li>
<li><code class="docutils literal notranslate"><span class="pre">break</span></code> would exit the match statement.</li>
</ul>
<p>However, there is a serious drawback to this proposal: if the <code class="docutils literal notranslate"><span class="pre">match</span></code> statement
is nested inside of a loop, the meanings of <code class="docutils literal notranslate"><span class="pre">continue</span></code> and <code class="docutils literal notranslate"><span class="pre">break</span></code> are now
changed. This may cause unexpected behavior during refactorings; also, an
argument can be made that there are other means to get the same behavior (such
as using guard conditions), and that in practice its likely that the existing
behavior of <code class="docutils literal notranslate"><span class="pre">continue</span></code> and <code class="docutils literal notranslate"><span class="pre">break</span></code> are far more useful.</p>
</section>
<section id="and-patterns">
<h3><a class="toc-backref" href="#and-patterns" role="doc-backlink">AND (<code class="docutils literal notranslate"><span class="pre">&amp;</span></code>) patterns</a></h3>
<p>This proposal defines an OR-pattern (<code class="docutils literal notranslate"><span class="pre">|</span></code>) to match one of several alternates;
why not also an AND-pattern (<code class="docutils literal notranslate"><span class="pre">&amp;</span></code>)? Especially given that some other languages
(F# for example) support this.</p>
<p>However, its not clear how useful this would be. The semantics for matching
dictionaries, objects and sequences already incorporates an implicit and: all
attributes and elements mentioned must be present for the match to succeed. Guard
conditions can also support many of the use cases that a hypothetical and
operator would be used for.</p>
<p>In the end, it was decided that this would make the syntax more complex without
adding a significant benefit.</p>
</section>
<section id="negative-match-patterns">
<h3><a class="toc-backref" href="#negative-match-patterns" role="doc-backlink">Negative match patterns</a></h3>
<p>A negation of a match pattern using the operator <code class="docutils literal notranslate"><span class="pre">!</span></code> as a prefix would match
exactly if the pattern itself does not match. For instance, <code class="docutils literal notranslate"><span class="pre">!(3</span> <span class="pre">|</span> <span class="pre">4)</span></code>
would match anything except <code class="docutils literal notranslate"><span class="pre">3</span></code> or <code class="docutils literal notranslate"><span class="pre">4</span></code>.</p>
<p>This was rejected because there is <a class="reference external" href="https://dl.acm.org/doi/abs/10.1145/2480360.2384582">documented evidence</a> that this feature
is rarely useful (in languages which support it) or used as double negation
<code class="docutils literal notranslate"><span class="pre">!!</span></code> to control variable scopes and prevent variable bindings (which does
not apply to Python). It can also be simulated using guard conditions.</p>
</section>
<section id="check-exhaustiveness-at-runtime">
<h3><a class="toc-backref" href="#check-exhaustiveness-at-runtime" role="doc-backlink">Check exhaustiveness at runtime</a></h3>
<p>The question is what to do if no case clause has a matching pattern, and
there is no default case. An earlier version of the proposal specified that
the behavior in this case would be to throw an exception rather than
silently falling through.</p>
<p>The arguments back and forth were many, but in the end the EIBTI (Explicit
Is Better Than Implicit) argument won out: its better to have the programmer
explicitly throw an exception if that is the behavior they want.</p>
<p>For cases such as sealed classes and enums, where the patterns are all known
to be members of a discrete set, <a class="reference internal" href="#static-checkers-specification">static checkers</a> can warn about missing
patterns.</p>
</section>
<section id="type-annotations-for-pattern-variables">
<h3><a class="toc-backref" href="#type-annotations-for-pattern-variables" role="doc-backlink">Type annotations for pattern variables</a></h3>
<p>The proposal was to combine patterns with type annotations:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">x</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="nb">int</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span> <span class="nb">str</span><span class="p">]:</span> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;An int </span><span class="si">{</span><span class="n">a</span><span class="si">}</span><span class="s2"> and a string </span><span class="si">{</span><span class="n">b</span><span class="si">}</span><span class="s2">:)</span>
<span class="k">case</span> <span class="p">[</span><span class="n">a</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">c</span><span class="p">:</span> <span class="nb">int</span><span class="p">]:</span> <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Three ints&quot;</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="n">c</span><span class="p">)</span>
<span class="o">...</span>
</pre></div>
</div>
<p>This idea has a lot of problems. For one, the colon can only
be used inside of brackets or parens, otherwise the syntax becomes
ambiguous. And because Python disallows <code class="docutils literal notranslate"><span class="pre">isinstance()</span></code> checks
on generic types, type annotations containing generics will not
work as expected.</p>
</section>
<section id="allow-rest-in-class-patterns">
<h3><a class="toc-backref" href="#allow-rest-in-class-patterns" role="doc-backlink">Allow <code class="docutils literal notranslate"><span class="pre">*rest</span></code> in class patterns</a></h3>
<p>It was proposed to allow <code class="docutils literal notranslate"><span class="pre">*rest</span></code> in a class pattern, giving a
variable to be bound to all positional arguments at once (similar to
its use in unpacking assignments). It would provide some symmetry
with sequence patterns. But it might be confused with a feature to
provide the <em>values</em> for all positional arguments at once. And there
seems to be no practical need for it, so it was scrapped. (It could
easily be added at a later stage if a need arises.)</p>
</section>
<section id="disallow-a-in-constant-value-patterns">
<h3><a class="toc-backref" href="#disallow-a-in-constant-value-patterns" role="doc-backlink">Disallow <code class="docutils literal notranslate"><span class="pre">_.a</span></code> in constant value patterns</a></h3>
<p>The first public draft said that the initial name in a constant value
pattern must not be <code class="docutils literal notranslate"><span class="pre">_</span></code> because <code class="docutils literal notranslate"><span class="pre">_</span></code> has a special meaning in
pattern matching, so this would be invalid:</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="o">.</span><span class="n">a</span><span class="p">:</span> <span class="o">...</span>
</pre></div>
</div>
<p>(However, <code class="docutils literal notranslate"><span class="pre">a._</span></code> would be legal and load the attribute with name
<code class="docutils literal notranslate"><span class="pre">_</span></code> of the object <code class="docutils literal notranslate"><span class="pre">a</span></code> as usual.)</p>
<p>There was some pushback against this on python-dev (some people have a
legitimate use for <code class="docutils literal notranslate"><span class="pre">_</span></code> as an important global variable, esp. in
i18n) and the only reason for this prohibition was to prevent some
user confusion. But its not the hill to die on.</p>
</section>
<section id="use-some-other-token-as-wildcard">
<h3><a class="toc-backref" href="#use-some-other-token-as-wildcard" role="doc-backlink">Use some other token as wildcard</a></h3>
<p>It has been proposed to use <code class="docutils literal notranslate"><span class="pre">...</span></code> (i.e., the ellipsis token) or
<code class="docutils literal notranslate"><span class="pre">*</span></code> (star) as a wildcard. However, both these look as if an
arbitrary number of items is omitted:</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="p">,</span> <span class="n">z</span><span class="p">]:</span> <span class="o">...</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="p">,</span> <span class="n">z</span><span class="p">]:</span> <span class="o">...</span>
</pre></div>
</div>
<p>Both look like the would match a sequence of at two or more items,
capturing the first and last values.</p>
<p>In addition, if <code class="docutils literal notranslate"><span class="pre">*</span></code> were to be used as the wildcard character, we
would have to come up with some other way to capture the rest of a
sequence, currently spelled like 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">first</span><span class="p">,</span> <span class="n">second</span><span class="p">,</span> <span class="o">*</span><span class="n">rest</span><span class="p">]:</span> <span class="o">...</span>
</pre></div>
</div>
<p>Using an ellipsis would also be more confusing in documentation and
examples, where <code class="docutils literal notranslate"><span class="pre">...</span></code> is routinely used to indicate something
obvious or irrelevant. (Yes, this would also be an argument against
the other uses of <code class="docutils literal notranslate"><span class="pre">...</span></code> in Python, but that water is already under
the bridge.)</p>
<p>Another proposal was to use <code class="docutils literal notranslate"><span class="pre">?</span></code>. This could be acceptable, although
it would require modifying the tokenizer.</p>
<p>Also, <code class="docutils literal notranslate"><span class="pre">_</span></code> is already used
as a throwaway target in other contexts, and this use is pretty
similar. This example is from <code class="docutils literal notranslate"><span class="pre">difflib.py</span></code> in the stdlib:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">tag</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">j1</span><span class="p">,</span> <span class="n">j2</span> <span class="ow">in</span> <span class="n">group</span><span class="p">:</span> <span class="o">...</span>
</pre></div>
</div>
<p>Perhaps the most convincing argument is that <code class="docutils literal notranslate"><span class="pre">_</span></code> is used as the
wildcard in every other language weve looked at supporting pattern
matching: C#, Elixir, Erlang, F#, Haskell, Mathematica, OCaml, Ruby,
Rust, Scala, and Swift. Now, in general, we should not be concerned
too much with what another language does, since Python is clearly
different from all these languages. However, if there is such an
overwhelming and strong consensus, Python should not go out of its way
to do something completely different particularly given that <code class="docutils literal notranslate"><span class="pre">_</span></code>
works well in Python and is already in use as a throwaway target.</p>
<p>Note that <code class="docutils literal notranslate"><span class="pre">_</span></code> is not assigned to by patterns this avoids
conflicts with the use of <code class="docutils literal notranslate"><span class="pre">_</span></code> as a marker for translatable strings
and an alias for <code class="docutils literal notranslate"><span class="pre">gettext.gettext</span></code>, as recommended by the
<code class="docutils literal notranslate"><span class="pre">gettext</span></code> module documentation.</p>
</section>
<section id="use-some-other-syntax-instead-of-for-or-patterns">
<h3><a class="toc-backref" href="#use-some-other-syntax-instead-of-for-or-patterns" role="doc-backlink">Use some other syntax instead of <code class="docutils literal notranslate"><span class="pre">|</span></code> for OR patterns</a></h3>
<p>A few alternatives to using <code class="docutils literal notranslate"><span class="pre">|</span></code> to separate the alternatives in OR
patterns have been proposed. Instead of:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">case</span> <span class="mi">401</span><span class="o">|</span><span class="mi">403</span><span class="o">|</span><span class="mi">404</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Some HTTP error&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>the following proposals have been fielded:</p>
<ul>
<li>Use a comma:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">case</span> <span class="mi">401</span><span class="p">,</span> <span class="mi">403</span><span class="p">,</span> <span class="mi">404</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Some HTTP error&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>This looks too much like a tuple we would have to find a
different way to spell tuples, and the construct would have to be
parenthesized inside the argument list of a class pattern. In
general, commas already have many different meanings in Python, we
shouldnt add more.</p>
</li>
<li>Allow stacked cases:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">case</span> <span class="mi">401</span><span class="p">:</span>
<span class="k">case</span> <span class="mi">403</span><span class="p">:</span>
<span class="k">case</span> <span class="mi">404</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Some HTTP error&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>This is how this would be done in C, using its fall-through
semantics for cases. However, we dont want to mislead people into
thinking that <code class="docutils literal notranslate"><span class="pre">match</span></code>/<code class="docutils literal notranslate"><span class="pre">case</span></code> uses fall-through semantics (which
are a common source of bugs in C). Also, this would be a novel
indentation pattern, which might make it harder to support in IDEs
and such (it would break the simple rule “add an indentation level
after a line ending in a colon”). Finally, this wouldnt support
OR patterns nested inside other patterns.</p>
</li>
<li>Use <code class="docutils literal notranslate"><span class="pre">case</span> <span class="pre">in</span></code> followed by a comma-separated list:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">case</span> <span class="ow">in</span> <span class="mi">401</span><span class="p">,</span> <span class="mi">403</span><span class="p">,</span> <span class="mi">404</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Some HTTP error&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>This wouldnt work for OR patterns nested inside other patterns,
like:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">case</span> <span class="n">Point</span><span class="p">(</span><span class="mi">0</span><span class="o">|</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="o">|</span><span class="mi">1</span><span class="p">):</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;A corner of the unit square&quot;</span><span class="p">)</span>
</pre></div>
</div>
</li>
<li>Use the <code class="docutils literal notranslate"><span class="pre">or</span></code> keyword:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">case</span> <span class="mi">401</span> <span class="ow">or</span> <span class="mi">403</span> <span class="ow">or</span> <span class="mi">404</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Some HTTP error&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>This could work, and the readability is not too different from using
<code class="docutils literal notranslate"><span class="pre">|</span></code>. Some users expressed a preference for <code class="docutils literal notranslate"><span class="pre">or</span></code> because they
associate <code class="docutils literal notranslate"><span class="pre">|</span></code> with bitwise OR. However:</p>
<ol class="arabic">
<li>Many other languages that have pattern matching use <code class="docutils literal notranslate"><span class="pre">|</span></code> (the
list includes Elixir, Erlang, F#, Mathematica, OCaml, Ruby, Rust,
and Scala).</li>
<li><code class="docutils literal notranslate"><span class="pre">|</span></code> is shorter, which may contribute to the readability of
nested patterns like <code class="docutils literal notranslate"><span class="pre">Point(0|1,</span> <span class="pre">0|1)</span></code>.</li>
<li>Some people mistakenly believe that <code class="docutils literal notranslate"><span class="pre">|</span></code> has the wrong priority;
but since patterns dont support other operators it has the same
priority as in expressions.</li>
<li>Python users use <code class="docutils literal notranslate"><span class="pre">or</span></code> very frequently, and may build an
impression that it is strongly associated with Boolean
short-circuiting.</li>
<li><code class="docutils literal notranslate"><span class="pre">|</span></code> is used between alternatives in regular expressions
and in EBNF grammars (like Pythons own).</li>
<li><code class="docutils literal notranslate"><span class="pre">|</span></code> not just used for bitwise OR its used for set unions,
dict merging (<a class="pep reference internal" href="../pep-0584/" title="PEP 584 Add Union Operators To dict">PEP 584</a>) and is being considered as an
alternative to <code class="docutils literal notranslate"><span class="pre">typing.Union</span></code> (<a class="pep reference internal" href="../pep-0604/" title="PEP 604 Allow writing union types as X | Y">PEP 604</a>).</li>
<li><code class="docutils literal notranslate"><span class="pre">|</span></code> works better as a visual separator, especially between
strings. Compare:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">case</span> <span class="s2">&quot;spam&quot;</span> <span class="ow">or</span> <span class="s2">&quot;eggs&quot;</span> <span class="ow">or</span> <span class="s2">&quot;cheese&quot;</span><span class="p">:</span>
</pre></div>
</div>
<p>to:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">case</span> <span class="s2">&quot;spam&quot;</span> <span class="o">|</span> <span class="s2">&quot;eggs&quot;</span> <span class="o">|</span> <span class="s2">&quot;cheese&quot;</span><span class="p">:</span>
</pre></div>
</div>
</li>
</ol>
</li>
</ul>
</section>
<section id="add-an-else-clause">
<h3><a class="toc-backref" href="#add-an-else-clause" role="doc-backlink">Add an <code class="docutils literal notranslate"><span class="pre">else</span></code> clause</a></h3>
<p>We decided not to add an <code class="docutils literal notranslate"><span class="pre">else</span></code> clause for several reasons.</p>
<ul class="simple">
<li>It is redundant, since we already have <code class="docutils literal notranslate"><span class="pre">case</span> <span class="pre">_:</span></code></li>
<li>There will forever be confusion about the indentation level of the
<code class="docutils literal notranslate"><span class="pre">else:</span></code> should it align with the list of cases or with the
<code class="docutils literal notranslate"><span class="pre">match</span></code> keyword?</li>
<li>Completionist arguments like “every other statement has one” are
false only those statements have an <code class="docutils literal notranslate"><span class="pre">else</span></code> clause where it adds
new functionality.</li>
</ul>
</section>
</section>
<section id="deferred-ideas">
<h2><a class="toc-backref" href="#deferred-ideas" role="doc-backlink">Deferred Ideas</a></h2>
<p>There were a number of proposals to extend the matching syntax that we
decided to postpone for possible future PEP. These fall into the realm of
“cool idea but not essential”, and it was felt that it might be better to
acquire some real-world data on how the match statement will be used in
practice before moving forward with some of these proposals.</p>
<p>Note that in each case, the idea was judged to be a “two-way door”,
meaning that there should be no backwards-compatibility issues with adding
these features later.</p>
<section id="one-off-syntax-variant">
<h3><a class="toc-backref" href="#one-off-syntax-variant" role="doc-backlink">One-off syntax variant</a></h3>
<p>While inspecting some code-bases that may benefit the most from the proposed
syntax, it was found that single clause matches would be used relatively often,
mostly for various special-casing. In other languages this is supported in
the form of one-off matches. We proposed to support such one-off matches too:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="n">match</span> <span class="n">value</span> <span class="k">as</span> <span class="n">pattern</span> <span class="p">[</span><span class="ow">and</span> <span class="n">guard</span><span class="p">]:</span>
<span class="o">...</span>
</pre></div>
</div>
<p>or, alternatively, without the <code class="docutils literal notranslate"><span class="pre">if</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">value</span> <span class="k">as</span> <span class="n">pattern</span> <span class="p">[</span><span class="k">if</span> <span class="n">guard</span><span class="p">]:</span>
<span class="o">...</span>
</pre></div>
</div>
<p>as equivalent to the following expansion:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">value</span><span class="p">:</span>
<span class="k">case</span> <span class="n">pattern</span> <span class="p">[</span><span class="k">if</span> <span class="n">guard</span><span class="p">]:</span>
<span class="o">...</span>
</pre></div>
</div>
<p>To illustrate how this will benefit readability, consider this (slightly
simplified) snippet from real code:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="n">CallExpr</span><span class="p">):</span>
<span class="k">if</span> <span class="p">(</span><span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="o">.</span><span class="n">callee</span><span class="p">,</span> <span class="n">NameExpr</span><span class="p">)</span> <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">node</span><span class="o">.</span><span class="n">args</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span> <span class="ow">and</span>
<span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="o">.</span><span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">NameExpr</span><span class="p">)):</span>
<span class="n">call</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="n">callee</span><span class="o">.</span><span class="n">name</span>
<span class="n">arg</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">name</span>
<span class="o">...</span> <span class="c1"># Continue special-casing &#39;call&#39; and &#39;arg&#39;</span>
<span class="o">...</span> <span class="c1"># Follow with common code</span>
</pre></div>
</div>
<p>This can be rewritten in a more straightforward way as:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="n">match</span> <span class="n">node</span> <span class="k">as</span> <span class="n">CallExpr</span><span class="p">(</span><span class="n">callee</span><span class="o">=</span><span class="n">NameExpr</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="n">call</span><span class="p">),</span> <span class="n">args</span><span class="o">=</span><span class="p">[</span><span class="n">NameExpr</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="n">arg</span><span class="p">)]):</span>
<span class="o">...</span> <span class="c1"># Continue special-casing &#39;call&#39; and &#39;arg&#39;</span>
<span class="o">...</span> <span class="c1"># Follow with common code</span>
</pre></div>
</div>
<p>This one-off form would not allow <code class="docutils literal notranslate"><span class="pre">elif</span> <span class="pre">match</span></code> statements, as it was only
meant to handle a single pattern case. It was intended to be special case
of a <code class="docutils literal notranslate"><span class="pre">match</span></code> statement, not a special case of an <code class="docutils literal notranslate"><span class="pre">if</span></code> statement:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="n">match</span> <span class="n">value_1</span> <span class="k">as</span> <span class="n">patter_1</span> <span class="p">[</span><span class="ow">and</span> <span class="n">guard_1</span><span class="p">]:</span>
<span class="o">...</span>
<span class="k">elif</span> <span class="n">match</span> <span class="n">value_2</span> <span class="k">as</span> <span class="n">pattern_2</span> <span class="p">[</span><span class="ow">and</span> <span class="n">guard_2</span><span class="p">]:</span> <span class="c1"># Not allowed</span>
<span class="o">...</span>
<span class="k">elif</span> <span class="n">match</span> <span class="n">value_3</span> <span class="k">as</span> <span class="n">pattern_3</span> <span class="p">[</span><span class="ow">and</span> <span class="n">guard_3</span><span class="p">]:</span> <span class="c1"># Not allowed</span>
<span class="o">...</span>
<span class="k">else</span><span class="p">:</span> <span class="c1"># Also not allowed</span>
<span class="o">...</span>
</pre></div>
</div>
<p>This would defeat the purpose of one-off matches as a complement to exhaustive
full matches - its better and clearer to use a full match in this case.</p>
<p>Similarly, <code class="docutils literal notranslate"><span class="pre">if</span> <span class="pre">not</span> <span class="pre">match</span></code> would not be allowed, since <code class="docutils literal notranslate"><span class="pre">match</span> <span class="pre">...</span> <span class="pre">as</span> <span class="pre">...</span></code> is not
an expression. Nor do we propose a <code class="docutils literal notranslate"><span class="pre">while</span> <span class="pre">match</span></code> construct present in some languages
with pattern matching, since although it may be handy, it will likely be used
rarely.</p>
</section>
<section id="other-pattern-based-constructions">
<h3><a class="toc-backref" href="#other-pattern-based-constructions" role="doc-backlink">Other pattern-based constructions</a></h3>
<p>Many other languages supporting pattern-matching use it as a basis for multiple
language constructs, including a matching operator, a generalized form
of assignment, a filter for loops, a method for synchronizing communication,
or specialized if statements. Some of these were mentioned in the discussion
of the first draft. Another question asked was why this particular form (joining
binding and conditional selection) was chosen while other forms were not.</p>
<p>Introducing more uses of patterns would be too bold and premature given the
experience we have using patterns, and would make this proposal too
complicated. The statement as presented provides a form of the feature that
is sufficiently general to be useful while being self-contained, and without
having a massive impact on the syntax and semantics of the language as a whole.</p>
<p>After some experience with this feature, the community may have a better
feeling for what other uses of pattern matching could be valuable in Python.</p>
</section>
<section id="algebraic-matching-of-repeated-names">
<h3><a class="toc-backref" href="#algebraic-matching-of-repeated-names" role="doc-backlink">Algebraic matching of repeated names</a></h3>
<p>A technique occasionally seen in functional languages like Erlang and Elixir is
to use a match variable multiple times in the same pattern:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">value</span><span class="p">:</span>
<span class="k">case</span> <span class="n">Point</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Point is on a diagonal!&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>The idea here is that the first appearance of <code class="docutils literal notranslate"><span class="pre">x</span></code> would bind the value
to the name, and subsequent occurrences would verify that the incoming
value was equal to the value previously bound. If the value was not equal,
the match would fail.</p>
<p>However, there are a number of subtleties involved with mixing load-store
semantics for capture patterns. For the moment, we decided to make repeated
use of names within the same pattern an error; we can always relax this
restriction later without affecting backwards compatibility.</p>
<p>Note that you <strong>can</strong> use the same name more than once in alternate choices:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">value</span><span class="p">:</span>
<span class="k">case</span> <span class="n">x</span> <span class="o">|</span> <span class="p">[</span><span class="n">x</span><span class="p">]:</span>
<span class="c1"># etc.</span>
</pre></div>
</div>
</section>
<section id="custom-matching-protocol">
<span id="extended-matching"></span><h3><a class="toc-backref" href="#custom-matching-protocol" role="doc-backlink">Custom matching protocol</a></h3>
<p>During the initial design discussions for this PEP, there were a lot of ideas
thrown around about custom matchers. There were a couple of motivations for
this:</p>
<ul class="simple">
<li>Some classes might want to expose a different set of “matchable” names
than the actual class properties.</li>
<li>Some classes might have properties that are expensive to calculate, and
therefore shouldnt be evaluated unless the match pattern actually needed
access to them.</li>
<li>There were ideas for exotic matchers such as <code class="docutils literal notranslate"><span class="pre">IsInstance()</span></code>,
<code class="docutils literal notranslate"><span class="pre">InRange()</span></code>, <code class="docutils literal notranslate"><span class="pre">RegexMatchingGroup()</span></code> and so on.</li>
<li>In order for built-in types and standard library classes to be able
to support matching in a reasonable and intuitive way, it was believed
that these types would need to implement special matching logic.</li>
</ul>
<p>These customized match behaviors would be controlled by a special
<code class="docutils literal notranslate"><span class="pre">__match__</span></code> method on the class name. There were two competing variants:</p>
<ul class="simple">
<li>A full-featured match protocol which would pass in not only
the subject to be matched, but detailed information about
which attributes the specified pattern was interested in.</li>
<li>A simplified match protocol, which only passed in the subject value,
and which returned a “proxy object” (which in most cases could be
just the subject) containing the matchable attributes.</li>
</ul>
<p>Heres an example of one version of the more complex protocol proposed:</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>
<span class="k">case</span> <span class="n">BinaryOp</span><span class="p">(</span><span class="n">left</span><span class="o">=</span><span class="n">Number</span><span class="p">(</span><span class="n">value</span><span class="o">=</span><span class="n">x</span><span class="p">),</span> <span class="n">op</span><span class="o">=</span><span class="n">op</span><span class="p">,</span> <span class="n">right</span><span class="o">=</span><span class="n">Number</span><span class="p">(</span><span class="n">value</span><span class="o">=</span><span class="n">y</span><span class="p">)):</span>
<span class="o">...</span>
<span class="kn">from</span> <span class="nn">types</span> <span class="kn">import</span> <span class="n">PatternObject</span>
<span class="n">BinaryOp</span><span class="o">.</span><span class="n">__match__</span><span class="p">(</span>
<span class="p">(),</span>
<span class="p">{</span>
<span class="s2">&quot;left&quot;</span><span class="p">:</span> <span class="n">PatternObject</span><span class="p">(</span><span class="n">Number</span><span class="p">,</span> <span class="p">(),</span> <span class="p">{</span><span class="s2">&quot;value&quot;</span><span class="p">:</span> <span class="o">...</span><span class="p">},</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="kc">False</span><span class="p">),</span>
<span class="s2">&quot;op&quot;</span><span class="p">:</span> <span class="o">...</span><span class="p">,</span>
<span class="s2">&quot;right&quot;</span><span class="p">:</span> <span class="n">PatternObject</span><span class="p">(</span><span class="n">Number</span><span class="p">,</span> <span class="p">(),</span> <span class="p">{</span><span class="s2">&quot;value&quot;</span><span class="p">:</span> <span class="o">...</span><span class="p">},</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="kc">False</span><span class="p">),</span>
<span class="p">},</span>
<span class="o">-</span><span class="mi">1</span><span class="p">,</span>
<span class="kc">False</span><span class="p">,</span>
<span class="p">)</span>
</pre></div>
</div>
<p>One drawback of this protocol is that the arguments to <code class="docutils literal notranslate"><span class="pre">__match__</span></code>
would be expensive to construct, and could not be pre-computed due to
the fact that, because of the way names are bound, there are no real
constants in Python. It also meant that the <code class="docutils literal notranslate"><span class="pre">__match__</span></code> method would
have to re-implement much of the logic of matching which would otherwise
be implemented in C code in the Python VM. As a result, this option would
perform poorly compared to an equivalent <code class="docutils literal notranslate"><span class="pre">if</span></code>-statement.</p>
<p>The simpler protocol suffered from the fact that although it was more
performant, it was much less flexible, and did not allow for many of
the creative custom matchers that people were dreaming up.</p>
<p>Late in the design process, however, it was realized that the need for
a custom matching protocol was much less than anticipated. Virtually
all the realistic (as opposed to fanciful) uses cases brought up could
be handled by the built-in matching behavior, although in a few cases
an extra guard condition was required to get the desired effect.</p>
<p>Moreover, it turned out that none of the standard library classes really
needed any special matching support other than an appropriate
<code class="docutils literal notranslate"><span class="pre">__match_args__</span></code> property.</p>
<p>The decision to postpone this feature came with a realization that this is
not a one-way door; that a more flexible and customizable matching protocol
can be added later, especially as we gain more experience with real-world
use cases and actual user needs.</p>
<p>The authors of this PEP expect that the <code class="docutils literal notranslate"><span class="pre">match</span></code> statement will evolve
over time as usage patterns and idioms evolve, in a way similar to what
other “multi-stage” PEPs have done in the past. When this happens, the
extended matching issue can be revisited.</p>
</section>
<section id="parameterized-matching-syntax">
<h3><a class="toc-backref" href="#parameterized-matching-syntax" role="doc-backlink">Parameterized Matching Syntax</a></h3>
<p>(Also known as “Class Instance Matchers”.)</p>
<p>This is another variant of the “custom match classes” idea that would allow
diverse kinds of custom matchers mentioned in the previous section however,
instead of using an extended matching protocol, it would be achieved by
introducing an additional pattern type with its own syntax. This pattern type
would accept two distinct sets of parameters: one set which consists of the
actual parameters passed into the pattern objects constructor, and another
set representing the binding variables for the pattern.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">__match__</span></code> method of these objects could use the constructor parameter
values in deciding what was a valid match.</p>
<p>This would allow patterns such as <code class="docutils literal notranslate"><span class="pre">InRange&lt;0,</span> <span class="pre">6&gt;(value)</span></code>, which would match
a number in the range 0..6 and assign the matched value to value. Similarly,
one could have a pattern which tests for the existence of a named group in
a regular expression match result (different meaning of the word match).</p>
<p>Although there is some support for this idea, there was a lot of bikeshedding
on the syntax (there are not a lot of attractive options available)
and no clear consensus was reached, so it was decided that for now, this
feature is not essential to the PEP.</p>
</section>
<section id="pattern-utility-library">
<h3><a class="toc-backref" href="#pattern-utility-library" role="doc-backlink">Pattern Utility Library</a></h3>
<p>Both of the previous ideas would be accompanied by a new Python standard
library module which would contain a rich set of useful matchers.
However, it is not really possible to implement such a library without
adopting one of the extended pattern proposals given in the previous sections,
so this idea is also deferred.</p>
</section>
</section>
<section id="acknowledgments">
<h2><a class="toc-backref" href="#acknowledgments" role="doc-backlink">Acknowledgments</a></h2>
<p>We are grateful for the help of the following individuals (among many
others) for helping out during various phases of the writing of this
PEP:</p>
<ul class="simple">
<li>Gregory P. Smith</li>
<li>Jim Jewett</li>
<li>Mark Shannon</li>
<li>Nate Lust</li>
<li>Taine Zhao</li>
</ul>
</section>
<section id="version-history">
<h2><a class="toc-backref" href="#version-history" role="doc-backlink">Version History</a></h2>
<ol class="arabic simple">
<li>Initial version</li>
<li>Substantial rewrite, including:<ul class="simple">
<li>Minor clarifications, grammar and typo corrections</li>
<li>Rename various concepts</li>
<li>Additional discussion of rejected ideas, including:<ul>
<li>Why we choose <code class="docutils literal notranslate"><span class="pre">_</span></code> for wildcard patterns</li>
<li>Why we choose <code class="docutils literal notranslate"><span class="pre">|</span></code> for OR patterns</li>
<li>Why we choose not to use special syntax for capture variables</li>
<li>Why this pattern matching operation and not others</li>
</ul>
</li>
<li>Clarify exception and side effect semantics</li>
<li>Clarify partial binding semantics</li>
<li>Drop restriction on use of <code class="docutils literal notranslate"><span class="pre">_</span></code> in load contexts</li>
<li>Drop the default single positional argument being the whole
subject except for a handful of built-in types</li>
<li>Simplify behavior of <code class="docutils literal notranslate"><span class="pre">__match_args__</span></code></li>
<li>Drop the <code class="docutils literal notranslate"><span class="pre">__match__</span></code> protocol (moved to <a class="reference internal" href="#deferred-ideas">deferred ideas</a>)</li>
<li>Drop <code class="docutils literal notranslate"><span class="pre">ImpossibleMatchError</span></code> exception</li>
<li>Drop leading dot for loads (moved to <a class="reference internal" href="#deferred-ideas">deferred ideas</a>)</li>
<li>Reworked the initial sections (everything before <a class="reference internal" href="#syntax-and-semantics">syntax</a>)</li>
<li>Added an overview of all the types of patterns before the
detailed description</li>
<li>Added simplified syntax next to the description of each pattern</li>
<li>Separate description of the wildcard from capture patterns</li>
<li>Added Daniel F Moisset as sixth co-author</li>
</ul>
</li>
</ol>
</section>
<section id="references">
<h2><a class="toc-backref" href="#references" role="doc-backlink">References</a></h2>
<aside class="footnote-list brackets">
<aside class="footnote brackets" id="id3" role="doc-footnote">
<dt class="label" id="id3">[<a href="#id2">1</a>]</dt>
<dd><a class="reference external" href="https://github.com/gvanrossum/patma/blob/master/EXAMPLES.md">https://github.com/gvanrossum/patma/blob/master/EXAMPLES.md</a></aside>
</aside>
</section>
<section id="appendix-a-full-grammar">
<h2><a class="toc-backref" href="#appendix-a-full-grammar" role="doc-backlink">Appendix A Full Grammar</a></h2>
<p>Here is the full grammar for <code class="docutils literal notranslate"><span class="pre">match_stmt</span></code>. This is an additional
alternative for <code class="docutils literal notranslate"><span class="pre">compound_stmt</span></code>. It should be understood that
<code class="docutils literal notranslate"><span class="pre">match</span></code> and <code class="docutils literal notranslate"><span class="pre">case</span></code> are soft keywords, i.e. they are not reserved
words in other grammatical contexts (including at the start of a line
if there is no colon where expected). By convention, hard keywords
use single quotes while soft keywords use double quotes.</p>
<p>Other notation used beyond standard EBNF:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">SEP.RULE+</span></code> is shorthand for <code class="docutils literal notranslate"><span class="pre">RULE</span> <span class="pre">(SEP</span> <span class="pre">RULE)*</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">!RULE</span></code> is a negative lookahead assertion</li>
</ul>
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>match_expr:
| star_named_expression &#39;,&#39; star_named_expressions?
| named_expression
match_stmt: &quot;match&quot; match_expr &#39;:&#39; NEWLINE INDENT case_block+ DEDENT
case_block: &quot;case&quot; patterns [guard] &#39;:&#39; block
guard: &#39;if&#39; named_expression
patterns: value_pattern &#39;,&#39; [values_pattern] | pattern
pattern: walrus_pattern | or_pattern
walrus_pattern: NAME &#39;:=&#39; or_pattern
or_pattern: &#39;|&#39;.closed_pattern+
closed_pattern:
| capture_pattern
| literal_pattern
| constant_pattern
| group_pattern
| sequence_pattern
| mapping_pattern
| class_pattern
capture_pattern: NAME !(&#39;.&#39; | &#39;(&#39; | &#39;=&#39;)
literal_pattern:
| signed_number !(&#39;+&#39; | &#39;-&#39;)
| signed_number &#39;+&#39; NUMBER
| signed_number &#39;-&#39; NUMBER
| strings
| &#39;None&#39;
| &#39;True&#39;
| &#39;False&#39;
constant_pattern: attr !(&#39;.&#39; | &#39;(&#39; | &#39;=&#39;)
group_pattern: &#39;(&#39; patterns &#39;)&#39;
sequence_pattern: &#39;[&#39; [values_pattern] &#39;]&#39; | &#39;(&#39; &#39;)&#39;
mapping_pattern: &#39;{&#39; items_pattern? &#39;}&#39;
class_pattern:
| name_or_attr &#39;(&#39; &#39;)&#39;
| name_or_attr &#39;(&#39; &#39;,&#39;.pattern+ &#39;,&#39;? &#39;)&#39;
| name_or_attr &#39;(&#39; &#39;,&#39;.keyword_pattern+ &#39;,&#39;? &#39;)&#39;
| name_or_attr &#39;(&#39; &#39;,&#39;.pattern+ &#39;,&#39; &#39;,&#39;.keyword_pattern+ &#39;,&#39;? &#39;)&#39;
signed_number: NUMBER | &#39;-&#39; NUMBER
attr: name_or_attr &#39;.&#39; NAME
name_or_attr: attr | NAME
values_pattern: &#39;,&#39;.value_pattern+ &#39;,&#39;?
items_pattern: &#39;,&#39;.key_value_pattern+ &#39;,&#39;?
keyword_pattern: NAME &#39;=&#39; or_pattern
value_pattern: &#39;*&#39; capture_pattern | pattern
key_value_pattern:
| (literal_pattern | constant_pattern) &#39;:&#39; or_pattern
| &#39;**&#39; capture_pattern
</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-0622.rst">https://github.com/python/peps/blob/main/peps/pep-0622.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0622.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><ul>
<li><a class="reference internal" href="#patterns-and-shapes">Patterns and shapes</a></li>
<li><a class="reference internal" href="#syntax">Syntax</a></li>
<li><a class="reference internal" href="#motivation">Motivation</a></li>
</ul>
</li>
<li><a class="reference internal" href="#overview">Overview</a><ul>
<li><a class="reference internal" href="#pattern-a-new-syntactic-construct-and-destructuring">Pattern, a new syntactic construct, and destructuring</a></li>
<li><a class="reference internal" href="#matching-process">Matching process</a></li>
</ul>
</li>
<li><a class="reference internal" href="#rationale-and-goals">Rationale and Goals</a></li>
<li><a class="reference internal" href="#syntax-and-semantics">Syntax and Semantics</a><ul>
<li><a class="reference internal" href="#patterns">Patterns</a></li>
<li><a class="reference internal" href="#the-match-statement">The <code class="docutils literal notranslate"><span class="pre">match</span></code> statement</a></li>
<li><a class="reference internal" href="#match-semantics">Match semantics</a></li>
<li><a class="reference internal" href="#allowed-patterns">Allowed patterns</a><ul>
<li><a class="reference internal" href="#literal-patterns">Literal Patterns</a></li>
<li><a class="reference internal" href="#capture-patterns">Capture Patterns</a></li>
<li><a class="reference internal" href="#wildcard-pattern">Wildcard Pattern</a></li>
<li><a class="reference internal" href="#constant-value-patterns">Constant 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>
</ul>
</li>
<li><a class="reference internal" href="#combining-multiple-patterns-or-patterns">Combining multiple patterns (OR patterns)</a></li>
<li><a class="reference internal" href="#guards">Guards</a></li>
<li><a class="reference internal" href="#walrus-patterns">Walrus patterns</a></li>
</ul>
</li>
<li><a class="reference internal" href="#runtime-specification">Runtime specification</a><ul>
<li><a class="reference internal" href="#the-match-protocol">The Match Protocol</a></li>
<li><a class="reference internal" href="#overlapping-sub-patterns">Overlapping sub-patterns</a></li>
<li><a class="reference internal" href="#special-attribute-match-args">Special attribute <code class="docutils literal notranslate"><span class="pre">__match_args__</span></code></a></li>
<li><a class="reference internal" href="#exceptions-and-side-effects">Exceptions and side effects</a></li>
<li><a class="reference internal" href="#the-standard-library">The standard library</a></li>
</ul>
</li>
<li><a class="reference internal" href="#static-checkers-specification">Static checkers specification</a><ul>
<li><a class="reference internal" href="#exhaustiveness-checks">Exhaustiveness checks</a></li>
<li><a class="reference internal" href="#sealed-classes-as-algebraic-data-types">Sealed classes as algebraic data types</a></li>
<li><a class="reference internal" href="#type-erasure">Type erasure</a></li>
<li><a class="reference internal" href="#note-about-constants">Note about constants</a></li>
<li><a class="reference internal" href="#precise-type-checking-of-star-matches">Precise type checking of star matches</a></li>
</ul>
</li>
<li><a class="reference internal" href="#performance-considerations">Performance Considerations</a></li>
<li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a></li>
<li><a class="reference internal" href="#impacts-on-third-party-tools">Impacts on third-party tools</a></li>
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li>
<li><a class="reference internal" href="#example-code">Example Code</a></li>
<li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul>
<li><a class="reference internal" href="#don-t-do-this-pattern-matching-is-hard-to-learn">Dont do this, pattern matching is hard to learn</a></li>
<li><a class="reference internal" href="#don-t-do-this-use-existing-method-dispatching-mechanisms">Dont do this, use existing method dispatching mechanisms</a></li>
<li><a class="reference internal" href="#allow-more-flexible-assignment-targets-instead">Allow more flexible assignment targets instead</a></li>
<li><a class="reference internal" href="#make-it-an-expression">Make it an expression</a></li>
<li><a class="reference internal" href="#use-a-hard-keyword">Use a hard keyword</a></li>
<li><a class="reference internal" href="#use-as-or-instead-of-case-for-case-clauses">Use <code class="docutils literal notranslate"><span class="pre">as</span></code> or <code class="docutils literal notranslate"><span class="pre">|</span></code> instead of <code class="docutils literal notranslate"><span class="pre">case</span></code> for case clauses</a></li>
<li><a class="reference internal" href="#use-a-flat-indentation-scheme">Use a flat indentation scheme</a></li>
<li><a class="reference internal" href="#alternatives-for-constant-value-pattern">Alternatives for constant value pattern</a></li>
<li><a class="reference internal" href="#disallow-float-literals-in-patterns">Disallow float literals in patterns</a></li>
<li><a class="reference internal" href="#range-matching-patterns">Range matching patterns</a></li>
<li><a class="reference internal" href="#use-dispatch-dict-semantics-for-matches">Use dispatch dict semantics for matches</a></li>
<li><a class="reference internal" href="#use-continue-and-break-in-case-clauses">Use <code class="docutils literal notranslate"><span class="pre">continue</span></code> and <code class="docutils literal notranslate"><span class="pre">break</span></code> in case clauses.</a></li>
<li><a class="reference internal" href="#and-patterns">AND (<code class="docutils literal notranslate"><span class="pre">&amp;</span></code>) patterns</a></li>
<li><a class="reference internal" href="#negative-match-patterns">Negative match patterns</a></li>
<li><a class="reference internal" href="#check-exhaustiveness-at-runtime">Check exhaustiveness at runtime</a></li>
<li><a class="reference internal" href="#type-annotations-for-pattern-variables">Type annotations for pattern variables</a></li>
<li><a class="reference internal" href="#allow-rest-in-class-patterns">Allow <code class="docutils literal notranslate"><span class="pre">*rest</span></code> in class patterns</a></li>
<li><a class="reference internal" href="#disallow-a-in-constant-value-patterns">Disallow <code class="docutils literal notranslate"><span class="pre">_.a</span></code> in constant value patterns</a></li>
<li><a class="reference internal" href="#use-some-other-token-as-wildcard">Use some other token as wildcard</a></li>
<li><a class="reference internal" href="#use-some-other-syntax-instead-of-for-or-patterns">Use some other syntax instead of <code class="docutils literal notranslate"><span class="pre">|</span></code> for OR patterns</a></li>
<li><a class="reference internal" href="#add-an-else-clause">Add an <code class="docutils literal notranslate"><span class="pre">else</span></code> clause</a></li>
</ul>
</li>
<li><a class="reference internal" href="#deferred-ideas">Deferred Ideas</a><ul>
<li><a class="reference internal" href="#one-off-syntax-variant">One-off syntax variant</a></li>
<li><a class="reference internal" href="#other-pattern-based-constructions">Other pattern-based constructions</a></li>
<li><a class="reference internal" href="#algebraic-matching-of-repeated-names">Algebraic matching of repeated names</a></li>
<li><a class="reference internal" href="#custom-matching-protocol">Custom matching protocol</a></li>
<li><a class="reference internal" href="#parameterized-matching-syntax">Parameterized Matching Syntax</a></li>
<li><a class="reference internal" href="#pattern-utility-library">Pattern Utility Library</a></li>
</ul>
</li>
<li><a class="reference internal" href="#acknowledgments">Acknowledgments</a></li>
<li><a class="reference internal" href="#version-history">Version History</a></li>
<li><a class="reference internal" href="#references">References</a></li>
<li><a class="reference internal" href="#appendix-a-full-grammar">Appendix A Full Grammar</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-0622.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>