python-peps/pep-0636/index.html

727 lines
76 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 636 Structural Pattern Matching: Tutorial | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-0636/">
<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 636 Structural Pattern Matching: Tutorial | peps.python.org'>
<meta property="og:description" content="This PEP is a tutorial for the pattern matching introduced by PEP 634.">
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-0636/">
<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 is a tutorial for the pattern matching introduced by PEP 634.">
<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 636</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 636 Structural Pattern Matching: Tutorial</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Daniel F Moisset &lt;dfmoisset&#32;&#97;t&#32;gmail.com&gt;</dd>
<dt class="field-even">Sponsor<span class="colon">:</span></dt>
<dd class="field-even">Guido van Rossum &lt;guido&#32;&#97;t&#32;python.org&gt;</dd>
<dt class="field-odd">BDFL-Delegate<span class="colon">:</span></dt>
<dd class="field-odd"><p></p></dd>
<dt class="field-even">Discussions-To<span class="colon">:</span></dt>
<dd class="field-even"><a class="reference external" href="https://mail.python.org/archives/list/python-dev&#64;python.org/">Python-Dev list</a></dd>
<dt class="field-odd">Status<span class="colon">:</span></dt>
<dd class="field-odd"><abbr title="Accepted and implementation complete, or no longer active">Final</abbr></dd>
<dt class="field-even">Type<span class="colon">:</span></dt>
<dd class="field-even"><abbr title="Non-normative PEP containing background, guidelines or other information relevant to the Python ecosystem">Informational</abbr></dd>
<dt class="field-odd">Created<span class="colon">:</span></dt>
<dd class="field-odd">12-Sep-2020</dd>
<dt class="field-even">Python-Version<span class="colon">:</span></dt>
<dd class="field-even">3.10</dd>
<dt class="field-odd">Post-History<span class="colon">:</span></dt>
<dd class="field-odd">22-Oct-2020, 08-Feb-2021</dd>
<dt class="field-even">Resolution<span class="colon">:</span></dt>
<dd class="field-even"><a class="reference external" href="https://mail.python.org/archives/list/python-committers&#64;python.org/message/SQC2FTLFV5A7DV7RCEAR2I2IKJKGK7W3">Python-Committers message</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></li>
<li><a class="reference internal" href="#tutorial">Tutorial</a><ul>
<li><a class="reference internal" href="#matching-sequences">Matching sequences</a></li>
<li><a class="reference internal" href="#matching-multiple-patterns">Matching multiple patterns</a></li>
<li><a class="reference internal" href="#matching-specific-values">Matching specific values</a></li>
<li><a class="reference internal" href="#matching-multiple-values">Matching multiple values</a></li>
<li><a class="reference internal" href="#adding-a-wildcard">Adding a wildcard</a></li>
<li><a class="reference internal" href="#composing-patterns">Composing patterns</a></li>
<li><a class="reference internal" href="#or-patterns">Or patterns</a></li>
<li><a class="reference internal" href="#capturing-matched-sub-patterns">Capturing matched sub-patterns</a></li>
<li><a class="reference internal" href="#adding-conditions-to-patterns">Adding conditions to patterns</a></li>
<li><a class="reference internal" href="#adding-a-ui-matching-objects">Adding a UI: Matching objects</a></li>
<li><a class="reference internal" href="#matching-positional-attributes">Matching positional attributes</a></li>
<li><a class="reference internal" href="#matching-against-constants-and-enums">Matching against constants and enums</a></li>
<li><a class="reference internal" href="#going-to-the-cloud-mappings">Going to the cloud: Mappings</a></li>
<li><a class="reference internal" href="#matching-builtin-classes">Matching builtin classes</a></li>
</ul>
</li>
<li><a class="reference internal" href="#appendix-a-quick-intro">Appendix A Quick Intro</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 is a tutorial for the pattern matching introduced by <a class="pep reference internal" href="../pep-0634/" title="PEP 634 Structural Pattern Matching: Specification">PEP 634</a>.</p>
<p><a class="pep reference internal" href="../pep-0622/" title="PEP 622 Structural Pattern Matching">PEP 622</a> proposed syntax for pattern matching, which received detailed discussion
both from the community and the Steering Council. A frequent concern was
about how easy it would be to explain (and learn) this feature. This PEP
addresses that concern providing the kind of document which developers could use
to learn about pattern matching in Python.</p>
<p>This is considered supporting material for <a class="pep reference internal" href="../pep-0634/" title="PEP 634 Structural Pattern Matching: Specification">PEP 634</a> (the technical specification
for pattern matching) and <a class="pep reference internal" href="../pep-0635/" title="PEP 635 Structural Pattern Matching: Motivation and Rationale">PEP 635</a> (the motivation and rationale for having pattern
matching and design considerations).</p>
<p>For readers who are looking more for a quick review than for a tutorial,
see <a class="reference internal" href="#pep-636-appendix-a">Appendix A</a>.</p>
</section>
<section id="tutorial">
<h2><a class="toc-backref" href="#tutorial" role="doc-backlink">Tutorial</a></h2>
<p>As an example to motivate this tutorial, you will be writing a text adventure. That is
a form of interactive fiction where the user enters text commands to interact with a
fictional world and receives text descriptions of what happens. Commands will be
simplified forms of natural language like <code class="docutils literal notranslate"><span class="pre">get</span> <span class="pre">sword</span></code>, <code class="docutils literal notranslate"><span class="pre">attack</span> <span class="pre">dragon</span></code>, <code class="docutils literal notranslate"><span class="pre">go</span> <span class="pre">north</span></code>,
<code class="docutils literal notranslate"><span class="pre">enter</span> <span class="pre">shop</span></code> or <code class="docutils literal notranslate"><span class="pre">buy</span> <span class="pre">cheese</span></code>.</p>
<section id="matching-sequences">
<h3><a class="toc-backref" href="#matching-sequences" role="doc-backlink">Matching sequences</a></h3>
<p>Your main loop will need to get input from the user and split it into words, lets say
a list of strings like this:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">command</span> <span class="o">=</span> <span class="nb">input</span><span class="p">(</span><span class="s2">&quot;What are you doing next? &quot;</span><span class="p">)</span>
<span class="c1"># analyze the result of command.split()</span>
</pre></div>
</div>
<p>The next step is to interpret the words. Most of our commands will have two words: an
action and an object. So you may be tempted to do the following:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[</span><span class="n">action</span><span class="p">,</span> <span class="n">obj</span><span class="p">]</span> <span class="o">=</span> <span class="n">command</span><span class="o">.</span><span class="n">split</span><span class="p">()</span>
<span class="o">...</span> <span class="c1"># interpret action, obj</span>
</pre></div>
</div>
<p>The problem with that line of code is that its missing something: what if the user
types more or fewer than 2 words? To prevent this problem you can either check the length
of the list of words, or capture the <code class="docutils literal notranslate"><span class="pre">ValueError</span></code> that the statement above would raise.</p>
<p>You can use a matching statement instead:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">command</span><span class="o">.</span><span class="n">split</span><span class="p">():</span>
<span class="k">case</span> <span class="p">[</span><span class="n">action</span><span class="p">,</span> <span class="n">obj</span><span class="p">]:</span>
<span class="o">...</span> <span class="c1"># interpret action, obj</span>
</pre></div>
</div>
<p>The match statement evaluates the <strong>“subject”</strong> (the value after the <code class="docutils literal notranslate"><span class="pre">match</span></code>
keyword), and checks it against the <strong>pattern</strong> (the code next to <code class="docutils literal notranslate"><span class="pre">case</span></code>). A pattern
is able to do two different things:</p>
<ul class="simple">
<li>Verify that the subject has certain structure. In your case, the <code class="docutils literal notranslate"><span class="pre">[action,</span> <span class="pre">obj]</span></code>
pattern matches any sequence of exactly two elements. This is called <strong>matching</strong></li>
<li>It will bind some names in the pattern to component elements of your subject. In
this case, if the list has two elements, it will bind <code class="docutils literal notranslate"><span class="pre">action</span> <span class="pre">=</span> <span class="pre">subject[0]</span></code> and
<code class="docutils literal notranslate"><span class="pre">obj</span> <span class="pre">=</span> <span class="pre">subject[1]</span></code>.</li>
</ul>
<p>If theres a match, the statements inside the case block will be executed with the
bound variables. If theres no match, nothing happens and the statement after
<code class="docutils literal notranslate"><span class="pre">match</span></code> is executed next.</p>
<p>Note that, in a similar way to unpacking assignments, you can use either parenthesis,
brackets, or just comma separation as synonyms. So you could write <code class="docutils literal notranslate"><span class="pre">case</span> <span class="pre">action,</span> <span class="pre">obj</span></code>
or <code class="docutils literal notranslate"><span class="pre">case</span> <span class="pre">(action,</span> <span class="pre">obj)</span></code> with the same meaning. All forms will match any sequence (for
example lists or tuples).</p>
</section>
<section id="matching-multiple-patterns">
<h3><a class="toc-backref" href="#matching-multiple-patterns" role="doc-backlink">Matching multiple patterns</a></h3>
<p>Even if most commands have the action/object form, you might want to have user commands
of different lengths. For example, you might want to add single verbs with no object like
<code class="docutils literal notranslate"><span class="pre">look</span></code> or <code class="docutils literal notranslate"><span class="pre">quit</span></code>. A match statement can (and is likely to) have more than one
<code class="docutils literal notranslate"><span class="pre">case</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">command</span><span class="o">.</span><span class="n">split</span><span class="p">():</span>
<span class="k">case</span> <span class="p">[</span><span class="n">action</span><span class="p">]:</span>
<span class="o">...</span> <span class="c1"># interpret single-verb action</span>
<span class="k">case</span> <span class="p">[</span><span class="n">action</span><span class="p">,</span> <span class="n">obj</span><span class="p">]:</span>
<span class="o">...</span> <span class="c1"># interpret action, obj</span>
</pre></div>
</div>
<p>The match statement will check patterns from top to bottom. If the pattern doesnt
match the subject, the next pattern will be tried. However, once the <em>first</em>
matching pattern is found, the body of that case is executed, and all further
cases are ignored. This is similar to the way that an <code class="docutils literal notranslate"><span class="pre">if/elif/elif/...</span></code>
statement works.</p>
</section>
<section id="matching-specific-values">
<h3><a class="toc-backref" href="#matching-specific-values" role="doc-backlink">Matching specific values</a></h3>
<p>Your code still needs to look at the specific actions and conditionally execute
different logic depending on the specific action (e.g., <code class="docutils literal notranslate"><span class="pre">quit</span></code>, <code class="docutils literal notranslate"><span class="pre">attack</span></code>, or <code class="docutils literal notranslate"><span class="pre">buy</span></code>).
You could do that using a chain of <code class="docutils literal notranslate"><span class="pre">if/elif/elif/...</span></code>, or using a dictionary of
functions, but here well leverage pattern matching to solve that task. Instead of a
variable, you can use literal values in patterns (like <code class="docutils literal notranslate"><span class="pre">&quot;quit&quot;</span></code>, <code class="docutils literal notranslate"><span class="pre">42</span></code>, or <code class="docutils literal notranslate"><span class="pre">None</span></code>).
This allows you to write:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">command</span><span class="o">.</span><span class="n">split</span><span class="p">():</span>
<span class="k">case</span> <span class="p">[</span><span class="s2">&quot;quit&quot;</span><span class="p">]:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Goodbye!&quot;</span><span class="p">)</span>
<span class="n">quit_game</span><span class="p">()</span>
<span class="k">case</span> <span class="p">[</span><span class="s2">&quot;look&quot;</span><span class="p">]:</span>
<span class="n">current_room</span><span class="o">.</span><span class="n">describe</span><span class="p">()</span>
<span class="k">case</span> <span class="p">[</span><span class="s2">&quot;get&quot;</span><span class="p">,</span> <span class="n">obj</span><span class="p">]:</span>
<span class="n">character</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">current_room</span><span class="p">)</span>
<span class="k">case</span> <span class="p">[</span><span class="s2">&quot;go&quot;</span><span class="p">,</span> <span class="n">direction</span><span class="p">]:</span>
<span class="n">current_room</span> <span class="o">=</span> <span class="n">current_room</span><span class="o">.</span><span class="n">neighbor</span><span class="p">(</span><span class="n">direction</span><span class="p">)</span>
<span class="c1"># The rest of your commands go here</span>
</pre></div>
</div>
<p>A pattern like <code class="docutils literal notranslate"><span class="pre">[&quot;get&quot;,</span> <span class="pre">obj]</span></code> will match only 2-element sequences that have a first
element equal to <code class="docutils literal notranslate"><span class="pre">&quot;get&quot;</span></code>. It will also bind <code class="docutils literal notranslate"><span class="pre">obj</span> <span class="pre">=</span> <span class="pre">subject[1]</span></code>.</p>
<p>As you can see in the <code class="docutils literal notranslate"><span class="pre">go</span></code> case, we also can use different variable names in
different patterns.</p>
<p>Literal values are compared with the <code class="docutils literal notranslate"><span class="pre">==</span></code> operator except for the constants <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> which are compared with the <code class="docutils literal notranslate"><span class="pre">is</span></code> operator.</p>
</section>
<section id="matching-multiple-values">
<h3><a class="toc-backref" href="#matching-multiple-values" role="doc-backlink">Matching multiple values</a></h3>
<p>A player may be able to drop multiple items by using a series of commands
<code class="docutils literal notranslate"><span class="pre">drop</span> <span class="pre">key</span></code>, <code class="docutils literal notranslate"><span class="pre">drop</span> <span class="pre">sword</span></code>, <code class="docutils literal notranslate"><span class="pre">drop</span> <span class="pre">cheese</span></code>. This interface might be cumbersome, and
you might like to allow dropping multiple items in a single command, like
<code class="docutils literal notranslate"><span class="pre">drop</span> <span class="pre">key</span> <span class="pre">sword</span> <span class="pre">cheese</span></code>. In this case you dont know beforehand how many words will
be in the command, but you can use extended unpacking in patterns in the same way that
they are allowed in assignments:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">command</span><span class="o">.</span><span class="n">split</span><span class="p">():</span>
<span class="k">case</span> <span class="p">[</span><span class="s2">&quot;drop&quot;</span><span class="p">,</span> <span class="o">*</span><span class="n">objects</span><span class="p">]:</span>
<span class="k">for</span> <span class="n">obj</span> <span class="ow">in</span> <span class="n">objects</span><span class="p">:</span>
<span class="n">character</span><span class="o">.</span><span class="n">drop</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">current_room</span><span class="p">)</span>
<span class="c1"># The rest of your commands go here</span>
</pre></div>
</div>
<p>This will match any sequences having “drop” as its first elements. All remaining
elements will be captured in a <code class="docutils literal notranslate"><span class="pre">list</span></code> object which will be bound to the <code class="docutils literal notranslate"><span class="pre">objects</span></code>
variable.</p>
<p>This syntax has similar restrictions as sequence unpacking: you can not have more than one
starred name in a pattern.</p>
</section>
<section id="adding-a-wildcard">
<h3><a class="toc-backref" href="#adding-a-wildcard" role="doc-backlink">Adding a wildcard</a></h3>
<p>You may want to print an error message saying that the command wasnt recognized when
all the patterns fail. You could use the feature we just learned and write
<code class="docutils literal notranslate"><span class="pre">case</span> <span class="pre">[*ignored_words]</span></code> as your last pattern. Theres however a much simpler way:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">command</span><span class="o">.</span><span class="n">split</span><span class="p">():</span>
<span class="k">case</span> <span class="p">[</span><span class="s2">&quot;quit&quot;</span><span class="p">]:</span> <span class="o">...</span> <span class="c1"># Code omitted for brevity</span>
<span class="k">case</span> <span class="p">[</span><span class="s2">&quot;go&quot;</span><span class="p">,</span> <span class="n">direction</span><span class="p">]:</span> <span class="o">...</span>
<span class="k">case</span> <span class="p">[</span><span class="s2">&quot;drop&quot;</span><span class="p">,</span> <span class="o">*</span><span class="n">objects</span><span class="p">]:</span> <span class="o">...</span>
<span class="o">...</span> <span class="c1"># Other cases</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="sa">f</span><span class="s2">&quot;Sorry, I couldn&#39;t understand </span><span class="si">{</span><span class="n">command</span><span class="si">!r}</span><span class="s2">&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>This special pattern which is written <code class="docutils literal notranslate"><span class="pre">_</span></code> (and called wildcard) always
matches but it doesnt bind any variables.</p>
<p>Note that this will match any object, not just sequences. As such, it only makes
sense to have it by itself as the last pattern (to prevent errors, Python will stop
you from using it before).</p>
</section>
<section id="composing-patterns">
<h3><a class="toc-backref" href="#composing-patterns" role="doc-backlink">Composing patterns</a></h3>
<p>This is a good moment to step back from the examples and understand how the patterns
that you have been using are built. Patterns can be nested within each other, and we
have been doing that implicitly in the examples above.</p>
<p>There are some “simple” patterns (“simple” here meaning that they do not contain other
patterns) that weve seen:</p>
<ul class="simple">
<li><strong>Capture patterns</strong> (stand-alone names like <code class="docutils literal notranslate"><span class="pre">direction</span></code>, <code class="docutils literal notranslate"><span class="pre">action</span></code>, <code class="docutils literal notranslate"><span class="pre">objects</span></code>). We
never discussed these separately, but used them as part of other patterns.</li>
<li><strong>Literal patterns</strong> (string literals, number literals, <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>)</li>
<li>The <strong>wildcard pattern</strong> <code class="docutils literal notranslate"><span class="pre">_</span></code></li>
</ul>
<p>Until now, the only non-simple pattern we have experimented with is the sequence pattern.
Each element in a sequence pattern can in fact be
any other pattern. This means that you could write a pattern like
<code class="docutils literal notranslate"><span class="pre">[&quot;first&quot;,</span> <span class="pre">(left,</span> <span class="pre">right),</span> <span class="pre">_,</span> <span class="pre">*rest]</span></code>. This will match subjects which are a sequence of at
least three elements, where the first one is equal to <code class="docutils literal notranslate"><span class="pre">&quot;first&quot;</span></code> and the second one is
in turn a sequence of two elements. It will also bind <code class="docutils literal notranslate"><span class="pre">left=subject[1][0]</span></code>,
<code class="docutils literal notranslate"><span class="pre">right=subject[1][1]</span></code>, and <code class="docutils literal notranslate"><span class="pre">rest</span> <span class="pre">=</span> <span class="pre">subject[3:]</span></code></p>
</section>
<section id="or-patterns">
<h3><a class="toc-backref" href="#or-patterns" role="doc-backlink">Or patterns</a></h3>
<p>Going back to the adventure game example, you may find that youd like to have several
patterns resulting in the same outcome. For example, you might want the commands
<code class="docutils literal notranslate"><span class="pre">north</span></code> and <code class="docutils literal notranslate"><span class="pre">go</span> <span class="pre">north</span></code> to be equivalent. You may also desire to have aliases for
<code class="docutils literal notranslate"><span class="pre">get</span> <span class="pre">X</span></code>, <code class="docutils literal notranslate"><span class="pre">pick</span> <span class="pre">up</span> <span class="pre">X</span></code> and <code class="docutils literal notranslate"><span class="pre">pick</span> <span class="pre">X</span> <span class="pre">up</span></code> for any X.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">|</span></code> symbol in patterns combines them as alternatives. You could for example write:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">command</span><span class="o">.</span><span class="n">split</span><span class="p">():</span>
<span class="o">...</span> <span class="c1"># Other cases</span>
<span class="k">case</span> <span class="p">[</span><span class="s2">&quot;north&quot;</span><span class="p">]</span> <span class="o">|</span> <span class="p">[</span><span class="s2">&quot;go&quot;</span><span class="p">,</span> <span class="s2">&quot;north&quot;</span><span class="p">]:</span>
<span class="n">current_room</span> <span class="o">=</span> <span class="n">current_room</span><span class="o">.</span><span class="n">neighbor</span><span class="p">(</span><span class="s2">&quot;north&quot;</span><span class="p">)</span>
<span class="k">case</span> <span class="p">[</span><span class="s2">&quot;get&quot;</span><span class="p">,</span> <span class="n">obj</span><span class="p">]</span> <span class="o">|</span> <span class="p">[</span><span class="s2">&quot;pick&quot;</span><span class="p">,</span> <span class="s2">&quot;up&quot;</span><span class="p">,</span> <span class="n">obj</span><span class="p">]</span> <span class="o">|</span> <span class="p">[</span><span class="s2">&quot;pick&quot;</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="s2">&quot;up&quot;</span><span class="p">]:</span>
<span class="o">...</span> <span class="c1"># Code for picking up the given object</span>
</pre></div>
</div>
<p>This is called an <strong>or pattern</strong> and will produce the expected result. Patterns are
tried from left to right; this may be relevant to know what is bound if more than
one alternative matches. An important restriction when writing or patterns is that all
alternatives should bind the same variables. So a pattern <code class="docutils literal notranslate"><span class="pre">[1,</span> <span class="pre">x]</span> <span class="pre">|</span> <span class="pre">[2,</span> <span class="pre">y]</span></code> is not
allowed because it would make unclear which variable would be bound after a successful
match. <code class="docutils literal notranslate"><span class="pre">[1,</span> <span class="pre">x]</span> <span class="pre">|</span> <span class="pre">[2,</span> <span class="pre">x]</span></code> is perfectly fine and will always bind <code class="docutils literal notranslate"><span class="pre">x</span></code> if successful.</p>
</section>
<section id="capturing-matched-sub-patterns">
<h3><a class="toc-backref" href="#capturing-matched-sub-patterns" role="doc-backlink">Capturing matched sub-patterns</a></h3>
<p>The first version of our “go” command was written with a <code class="docutils literal notranslate"><span class="pre">[&quot;go&quot;,</span> <span class="pre">direction]</span></code> pattern.
The change we did in our last version using the pattern <code class="docutils literal notranslate"><span class="pre">[&quot;north&quot;]</span> <span class="pre">|</span> <span class="pre">[&quot;go&quot;,</span> <span class="pre">&quot;north&quot;]</span></code>
has some benefits but also some drawbacks in comparison: the latest version allows the
alias, but also has the direction hardcoded, which will force us to actually have
separate patterns for north/south/east/west. This leads to some code duplication, but at
the same time we get better input validation, and we will not be getting into that
branch if the command entered by the user is <code class="docutils literal notranslate"><span class="pre">&quot;go</span> <span class="pre">figure!&quot;</span></code> instead of a direction.</p>
<p>We could try to get the best of both worlds doing the following (Ill omit the aliased
version without “go” for brevity):</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">command</span><span class="o">.</span><span class="n">split</span><span class="p">():</span>
<span class="k">case</span> <span class="p">[</span><span class="s2">&quot;go&quot;</span><span class="p">,</span> <span class="p">(</span><span class="s2">&quot;north&quot;</span> <span class="o">|</span> <span class="s2">&quot;south&quot;</span> <span class="o">|</span> <span class="s2">&quot;east&quot;</span> <span class="o">|</span> <span class="s2">&quot;west&quot;</span><span class="p">)]:</span>
<span class="n">current_room</span> <span class="o">=</span> <span class="n">current_room</span><span class="o">.</span><span class="n">neighbor</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="c1"># how do I know which direction to go?</span>
</pre></div>
</div>
<p>This code is a single branch, and it verifies that the word after “go” is really a
direction. But the code moving the player around needs to know which one was chosen and
has no way to do so. What we need is a pattern that behaves like the or pattern but at
the same time does a capture. We can do so with an <strong>as pattern</strong>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">command</span><span class="o">.</span><span class="n">split</span><span class="p">():</span>
<span class="k">case</span> <span class="p">[</span><span class="s2">&quot;go&quot;</span><span class="p">,</span> <span class="p">(</span><span class="s2">&quot;north&quot;</span> <span class="o">|</span> <span class="s2">&quot;south&quot;</span> <span class="o">|</span> <span class="s2">&quot;east&quot;</span> <span class="o">|</span> <span class="s2">&quot;west&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">direction</span><span class="p">]:</span>
<span class="n">current_room</span> <span class="o">=</span> <span class="n">current_room</span><span class="o">.</span><span class="n">neighbor</span><span class="p">(</span><span class="n">direction</span><span class="p">)</span>
</pre></div>
</div>
<p>The as-pattern matches whatever pattern is on its left-hand side, but also binds the
value to a name.</p>
</section>
<section id="adding-conditions-to-patterns">
<h3><a class="toc-backref" href="#adding-conditions-to-patterns" role="doc-backlink">Adding conditions to patterns</a></h3>
<p>The patterns we have explored above can do some powerful data filtering, but sometimes
you may wish for the full power of a boolean expression. Lets say that you would actually
like to allow a “go” command only in a restricted set of directions based on the possible
exits from the current_room. We can achieve that by adding a <strong>guard</strong> to our
case. Guards consist of the <code class="docutils literal notranslate"><span class="pre">if</span></code> keyword followed by any expression:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">command</span><span class="o">.</span><span class="n">split</span><span class="p">():</span>
<span class="k">case</span> <span class="p">[</span><span class="s2">&quot;go&quot;</span><span class="p">,</span> <span class="n">direction</span><span class="p">]</span> <span class="k">if</span> <span class="n">direction</span> <span class="ow">in</span> <span class="n">current_room</span><span class="o">.</span><span class="n">exits</span><span class="p">:</span>
<span class="n">current_room</span> <span class="o">=</span> <span class="n">current_room</span><span class="o">.</span><span class="n">neighbor</span><span class="p">(</span><span class="n">direction</span><span class="p">)</span>
<span class="k">case</span><span class="w"> </span><span class="p">[</span><span class="s2">&quot;go&quot;</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;Sorry, you can&#39;t go that way&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>The guard is not part of the pattern, its part of the case. Its only checked if
the pattern matches, and after all the pattern variables have been bound (thats why the
condition can use the <code class="docutils literal notranslate"><span class="pre">direction</span></code> variable in the example above). If the pattern
matches and the condition is truthy, the body of the case executes normally. If the
pattern matches but the condition is falsy, the match statement proceeds to check the
next case as if the pattern hadnt matched (with the possible side-effect of
having already bound some variables).</p>
</section>
<section id="adding-a-ui-matching-objects">
<h3><a class="toc-backref" href="#adding-a-ui-matching-objects" role="doc-backlink">Adding a UI: Matching objects</a></h3>
<p>Your adventure is becoming a success and you have been asked to implement a graphical
interface. Your UI toolkit of choice allows you to write an event loop where you can get a new
event object by calling <code class="docutils literal notranslate"><span class="pre">event.get()</span></code>. The resulting object can have different type and
attributes according to the user action, for example:</p>
<ul class="simple">
<li>A <code class="docutils literal notranslate"><span class="pre">KeyPress</span></code> object is generated when the user presses a key. It has a <code class="docutils literal notranslate"><span class="pre">key_name</span></code>
attribute with the name of the key pressed, and some other attributes regarding modifiers.</li>
<li>A <code class="docutils literal notranslate"><span class="pre">Click</span></code> object is generated when the user clicks the mouse. It has an attribute
<code class="docutils literal notranslate"><span class="pre">position</span></code> with the coordinates of the pointer.</li>
<li>A <code class="docutils literal notranslate"><span class="pre">Quit</span></code> object is generated when the user clicks on the close button for the game
window.</li>
</ul>
<p>Rather than writing multiple <code class="docutils literal notranslate"><span class="pre">isinstance()</span></code> checks, you can use patterns to recognize
different kinds of objects, and also apply patterns to its attributes:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">event</span><span class="o">.</span><span class="n">get</span><span class="p">():</span>
<span class="k">case</span> <span class="n">Click</span><span class="p">(</span><span class="n">position</span><span class="o">=</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">handle_click_at</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">case</span> <span class="n">KeyPress</span><span class="p">(</span><span class="n">key_name</span><span class="o">=</span><span class="s2">&quot;Q&quot;</span><span class="p">)</span> <span class="o">|</span> <span class="n">Quit</span><span class="p">():</span>
<span class="n">game</span><span class="o">.</span><span class="n">quit</span><span class="p">()</span>
<span class="k">case</span> <span class="n">KeyPress</span><span class="p">(</span><span class="n">key_name</span><span class="o">=</span><span class="s2">&quot;up arrow&quot;</span><span class="p">):</span>
<span class="n">game</span><span class="o">.</span><span class="n">go_north</span><span class="p">()</span>
<span class="o">...</span>
<span class="k">case</span> <span class="n">KeyPress</span><span class="p">():</span>
<span class="k">pass</span> <span class="c1"># Ignore other keystrokes</span>
<span class="k">case</span> <span class="n">other_event</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Unrecognized event: </span><span class="si">{</span><span class="n">other_event</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>A pattern like <code class="docutils literal notranslate"><span class="pre">Click(position=(x,</span> <span class="pre">y))</span></code> only matches if the type of the event is
a subclass of the <code class="docutils literal notranslate"><span class="pre">Click</span></code> class. It will also require that the event has a <code class="docutils literal notranslate"><span class="pre">position</span></code>
attribute that matches the <code class="docutils literal notranslate"><span class="pre">(x,</span> <span class="pre">y)</span></code> pattern. If theres a match, the locals <code class="docutils literal notranslate"><span class="pre">x</span></code> and
<code class="docutils literal notranslate"><span class="pre">y</span></code> will get the expected values.</p>
<p>A pattern like <code class="docutils literal notranslate"><span class="pre">KeyPress()</span></code>, with no arguments will match any object which is an
instance of the <code class="docutils literal notranslate"><span class="pre">KeyPress</span></code> class. Only the attributes you specify in the pattern are
matched, and any other attributes are ignored.</p>
</section>
<section id="matching-positional-attributes">
<h3><a class="toc-backref" href="#matching-positional-attributes" role="doc-backlink">Matching positional attributes</a></h3>
<p>The previous section described how to match named attributes when doing an object match.
For some objects it could be convenient to describe the matched arguments by position
(especially if there are only a few attributes and they have a “standard” ordering).
If the classes that you are using are named tuples or dataclasses, you can do that by
following the same order that youd use when constructing an object. For example, if
the UI framework above defines their class like this:</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="nd">@dataclass</span>
<span class="k">class</span> <span class="nc">Click</span><span class="p">:</span>
<span class="n">position</span><span class="p">:</span> <span class="nb">tuple</span>
<span class="n">button</span><span class="p">:</span> <span class="n">Button</span>
</pre></div>
</div>
<p>then you can rewrite your match statement above as:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">event</span><span class="o">.</span><span class="n">get</span><span class="p">():</span>
<span class="k">case</span> <span class="n">Click</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">handle_click_at</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 <code class="docutils literal notranslate"><span class="pre">(x,</span> <span class="pre">y)</span></code> pattern will be automatically matched against the <code class="docutils literal notranslate"><span class="pre">position</span></code>
attribute, because the first argument in the pattern corresponds to the first
attribute in your dataclass definition.</p>
<p>Other classes dont have a natural ordering of their attributes so youre required to
use explicit names in your pattern to match with their attributes. However, its possible
to manually specify the ordering of the attributes allowing positional matching, like in
this alternative definition:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Click</span><span class="p">:</span>
<span class="n">__match_args__</span> <span class="o">=</span> <span class="p">(</span><span class="s2">&quot;position&quot;</span><span class="p">,</span> <span class="s2">&quot;button&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">pos</span><span class="p">,</span> <span class="n">btn</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">position</span> <span class="o">=</span> <span class="n">pos</span>
<span class="bp">self</span><span class="o">.</span><span class="n">button</span> <span class="o">=</span> <span class="n">btn</span>
<span class="o">...</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">__match_args__</span></code> special attribute defines an explicit order for your attributes
that can be used in patterns like <code class="docutils literal notranslate"><span class="pre">case</span> <span class="pre">Click((x,y))</span></code>.</p>
</section>
<section id="matching-against-constants-and-enums">
<h3><a class="toc-backref" href="#matching-against-constants-and-enums" role="doc-backlink">Matching against constants and enums</a></h3>
<p>Your pattern above treats all mouse buttons the same, and you have decided that you
want to accept left-clicks, and ignore other buttons. While doing so, you notice that
the <code class="docutils literal notranslate"><span class="pre">button</span></code> attribute is typed as a <code class="docutils literal notranslate"><span class="pre">Button</span></code> which is an enumeration built with
<code class="docutils literal notranslate"><span class="pre">enum.Enum</span></code>. You can in fact match against enumeration values like this:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">event</span><span class="o">.</span><span class="n">get</span><span class="p">():</span>
<span class="k">case</span> <span class="n">Click</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">button</span><span class="o">=</span><span class="n">Button</span><span class="o">.</span><span class="n">LEFT</span><span class="p">):</span> <span class="c1"># This is a left click</span>
<span class="n">handle_click_at</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">case</span> <span class="n">Click</span><span class="p">():</span>
<span class="k">pass</span> <span class="c1"># ignore other clicks</span>
</pre></div>
</div>
<p>This will work with any dotted name (like <code class="docutils literal notranslate"><span class="pre">math.pi</span></code>). However an unqualified name (i.e.
a bare name with no dots) will be always interpreted as a capture pattern, so avoid
that ambiguity by always using qualified constants in patterns.</p>
</section>
<section id="going-to-the-cloud-mappings">
<h3><a class="toc-backref" href="#going-to-the-cloud-mappings" role="doc-backlink">Going to the cloud: Mappings</a></h3>
<p>You have decided to make an online version of your game. All
of your logic will be in a server, and the UI in a client which will communicate using
JSON messages. Via the <code class="docutils literal notranslate"><span class="pre">json</span></code> module, those will be mapped to Python dictionaries,
lists and other builtin objects.</p>
<p>Our client will receive a list of dictionaries (parsed from JSON) of actions to take,
each element looking for example like these:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">{&quot;text&quot;:</span> <span class="pre">&quot;The</span> <span class="pre">shop</span> <span class="pre">keeper</span> <span class="pre">says</span> <span class="pre">'Ah!</span> <span class="pre">We</span> <span class="pre">have</span> <span class="pre">Camembert,</span> <span class="pre">yes</span> <span class="pre">sir'&quot;,</span> <span class="pre">&quot;color&quot;:</span> <span class="pre">&quot;blue&quot;}</span></code></li>
<li>If the client should make a pause <code class="docutils literal notranslate"><span class="pre">{&quot;sleep&quot;:</span> <span class="pre">3}</span></code></li>
<li>To play a sound <code class="docutils literal notranslate"><span class="pre">{&quot;sound&quot;:</span> <span class="pre">&quot;filename.ogg&quot;,</span> <span class="pre">&quot;format&quot;:</span> <span class="pre">&quot;ogg&quot;}</span></code></li>
</ul>
<p>Until now, our patterns have processed sequences, but there are patterns to match
mappings based on their present keys. In this case you could use:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">action</span> <span class="ow">in</span> <span class="n">actions</span><span class="p">:</span>
<span class="k">match</span> <span class="n">action</span><span class="p">:</span>
<span class="k">case</span> <span class="p">{</span><span class="s2">&quot;text&quot;</span><span class="p">:</span> <span class="n">message</span><span class="p">,</span> <span class="s2">&quot;color&quot;</span><span class="p">:</span> <span class="n">c</span><span class="p">}:</span>
<span class="n">ui</span><span class="o">.</span><span class="n">set_text_color</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>
<span class="n">ui</span><span class="o">.</span><span class="n">display</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
<span class="k">case</span> <span class="p">{</span><span class="s2">&quot;sleep&quot;</span><span class="p">:</span> <span class="n">duration</span><span class="p">}:</span>
<span class="n">ui</span><span class="o">.</span><span class="n">wait</span><span class="p">(</span><span class="n">duration</span><span class="p">)</span>
<span class="k">case</span> <span class="p">{</span><span class="s2">&quot;sound&quot;</span><span class="p">:</span> <span class="n">url</span><span class="p">,</span> <span class="s2">&quot;format&quot;</span><span class="p">:</span> <span class="s2">&quot;ogg&quot;</span><span class="p">}:</span>
<span class="n">ui</span><span class="o">.</span><span class="n">play</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
<span class="k">case</span><span class="w"> </span><span class="p">{</span><span class="s2">&quot;sound&quot;</span><span class="p">:</span> <span class="k">_</span><span class="p">,</span> <span class="s2">&quot;format&quot;</span><span class="p">:</span> <span class="n">_</span><span class="p">}:</span>
<span class="n">warning</span><span class="p">(</span><span class="s2">&quot;Unsupported audio format&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>The keys in your mapping pattern need to be literals, but the values can be any
pattern. As in sequence patterns, all subpatterns have to match for the general
pattern to match.</p>
<p>You can use <code class="docutils literal notranslate"><span class="pre">**rest</span></code> within a mapping pattern to capture additional keys in
the subject. Note that if you omit this, extra keys in the subject will be
ignored while matching, i.e. the message
<code class="docutils literal notranslate"><span class="pre">{&quot;text&quot;:</span> <span class="pre">&quot;foo&quot;,</span> <span class="pre">&quot;color&quot;:</span> <span class="pre">&quot;red&quot;,</span> <span class="pre">&quot;style&quot;:</span> <span class="pre">&quot;bold&quot;}</span></code> will match the first pattern
in the example above.</p>
</section>
<section id="matching-builtin-classes">
<h3><a class="toc-backref" href="#matching-builtin-classes" role="doc-backlink">Matching builtin classes</a></h3>
<p>The code above could use some validation. Given that messages came from an external
source, the types of the field could be wrong, leading to bugs or security issues.</p>
<p>Any class is a valid match target, and that includes built-in classes like <code class="docutils literal notranslate"><span class="pre">bool</span></code>
<code class="docutils literal notranslate"><span class="pre">str</span></code> or <code class="docutils literal notranslate"><span class="pre">int</span></code>. That allows us to combine the code above with a class pattern.
So instead of writing <code class="docutils literal notranslate"><span class="pre">{&quot;text&quot;:</span> <span class="pre">message,</span> <span class="pre">&quot;color&quot;:</span> <span class="pre">c}</span></code> we can use
<code class="docutils literal notranslate"><span class="pre">{&quot;text&quot;:</span> <span class="pre">str()</span> <span class="pre">as</span> <span class="pre">message,</span> <span class="pre">&quot;color&quot;:</span> <span class="pre">str()</span> <span class="pre">as</span> <span class="pre">c}</span></code> to ensure that <code class="docutils literal notranslate"><span class="pre">message</span></code> and <code class="docutils literal notranslate"><span class="pre">c</span></code>
are both strings. For many builtin classes (see <a class="pep reference internal" href="../pep-0634/" title="PEP 634 Structural Pattern Matching: Specification">PEP 634</a> for the whole list), you can
use a positional parameter as a shorthand, writing <code class="docutils literal notranslate"><span class="pre">str(c)</span></code> rather than <code class="docutils literal notranslate"><span class="pre">str()</span> <span class="pre">as</span> <span class="pre">c</span></code>.
The fully rewritten version looks like this:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">action</span> <span class="ow">in</span> <span class="n">actions</span><span class="p">:</span>
<span class="k">match</span> <span class="n">action</span><span class="p">:</span>
<span class="k">case</span> <span class="p">{</span><span class="s2">&quot;text&quot;</span><span class="p">:</span> <span class="nb">str</span><span class="p">(</span><span class="n">message</span><span class="p">),</span> <span class="s2">&quot;color&quot;</span><span class="p">:</span> <span class="nb">str</span><span class="p">(</span><span class="n">c</span><span class="p">)}:</span>
<span class="n">ui</span><span class="o">.</span><span class="n">set_text_color</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>
<span class="n">ui</span><span class="o">.</span><span class="n">display</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
<span class="k">case</span> <span class="p">{</span><span class="s2">&quot;sleep&quot;</span><span class="p">:</span> <span class="nb">float</span><span class="p">(</span><span class="n">duration</span><span class="p">)}:</span>
<span class="n">ui</span><span class="o">.</span><span class="n">wait</span><span class="p">(</span><span class="n">duration</span><span class="p">)</span>
<span class="k">case</span> <span class="p">{</span><span class="s2">&quot;sound&quot;</span><span class="p">:</span> <span class="nb">str</span><span class="p">(</span><span class="n">url</span><span class="p">),</span> <span class="s2">&quot;format&quot;</span><span class="p">:</span> <span class="s2">&quot;ogg&quot;</span><span class="p">}:</span>
<span class="n">ui</span><span class="o">.</span><span class="n">play</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
<span class="k">case</span><span class="w"> </span><span class="p">{</span><span class="s2">&quot;sound&quot;</span><span class="p">:</span> <span class="k">_</span><span class="p">,</span> <span class="s2">&quot;format&quot;</span><span class="p">:</span> <span class="n">_</span><span class="p">}:</span>
<span class="n">warning</span><span class="p">(</span><span class="s2">&quot;Unsupported audio format&quot;</span><span class="p">)</span>
</pre></div>
</div>
</section>
</section>
<section id="appendix-a-quick-intro">
<span id="pep-636-appendix-a"></span><h2><a class="toc-backref" href="#appendix-a-quick-intro" role="doc-backlink">Appendix A Quick Intro</a></h2>
<p>A match statement takes an expression and compares its value to successive
patterns given as one or more case blocks. This is superficially
similar to a switch statement in C, Java or JavaScript (and many
other languages), but much more powerful.</p>
<p>The simplest form compares a subject value against one or more literals:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">http_error</span><span class="p">(</span><span class="n">status</span><span class="p">):</span>
<span class="k">match</span> <span class="n">status</span><span class="p">:</span>
<span class="k">case</span> <span class="mi">400</span><span class="p">:</span>
<span class="k">return</span> <span class="s2">&quot;Bad request&quot;</span>
<span class="k">case</span> <span class="mi">404</span><span class="p">:</span>
<span class="k">return</span> <span class="s2">&quot;Not found&quot;</span>
<span class="k">case</span> <span class="mi">418</span><span class="p">:</span>
<span class="k">return</span> <span class="s2">&quot;I&#39;m a teapot&quot;</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="s2">&quot;Something&#39;s wrong with the Internet&quot;</span>
</pre></div>
</div>
<p>Note the last block: the “variable name” <code class="docutils literal notranslate"><span class="pre">_</span></code> acts as a <em>wildcard</em> and
never fails to match.</p>
<p>You can combine several literals in a single pattern using <code class="docutils literal notranslate"><span class="pre">|</span></code> (“or”):</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="k">return</span> <span class="s2">&quot;Not allowed&quot;</span>
</pre></div>
</div>
<p>Patterns can look like unpacking assignments, and can be used to bind
variables:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># point is an (x, y) tuple</span>
<span class="k">match</span> <span class="n">point</span><span class="p">:</span>
<span class="k">case</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">):</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Origin&quot;</span><span class="p">)</span>
<span class="k">case</span> <span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">y</span><span class="p">):</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Y=</span><span class="si">{</span><span class="n">y</span><span class="si">}</span><span class="s2">&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="mi">0</span><span class="p">):</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;X=</span><span class="si">{</span><span class="n">x</span><span class="si">}</span><span class="s2">&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="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;X=</span><span class="si">{</span><span class="n">x</span><span class="si">}</span><span class="s2">, Y=</span><span class="si">{</span><span class="n">y</span><span class="si">}</span><span class="s2">&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="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;Not a point&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>Study that one carefully! The first pattern has two literals, and can
be thought of as an extension of the literal pattern shown above. But
the next two patterns combine a literal and a variable, and the
variable <em>binds</em> a value from the subject (<code class="docutils literal notranslate"><span class="pre">point</span></code>). The fourth
pattern captures two values, which makes it conceptually similar to
the unpacking assignment <code class="docutils literal notranslate"><span class="pre">(x,</span> <span class="pre">y)</span> <span class="pre">=</span> <span class="pre">point</span></code>.</p>
<p>If you are using classes to structure your data
you can use the class name followed by an argument list resembling a
constructor, but with the ability to capture attributes into variables:</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="nd">@dataclass</span>
<span class="k">class</span> <span class="nc">Point</span><span class="p">:</span>
<span class="n">x</span><span class="p">:</span> <span class="nb">int</span>
<span class="n">y</span><span class="p">:</span> <span class="nb">int</span>
<span class="k">def</span> <span class="nf">where_is</span><span class="p">(</span><span class="n">point</span><span class="p">):</span>
<span class="k">match</span> <span class="n">point</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="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">y</span><span class="o">=</span><span class="mi">0</span><span class="p">):</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Origin&quot;</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="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">y</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="sa">f</span><span class="s2">&quot;Y=</span><span class="si">{</span><span class="n">y</span><span class="si">}</span><span class="s2">&quot;</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="o">=</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="o">=</span><span class="mi">0</span><span class="p">):</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;X=</span><span class="si">{</span><span class="n">x</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
<span class="k">case</span> <span class="n">Point</span><span class="p">():</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Somewhere else&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 a point&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>You can use positional parameters with some builtin classes that provide an
ordering for their attributes (e.g. dataclasses). You can also define a specific
position for attributes in patterns by setting the <code class="docutils literal notranslate"><span class="pre">__match_args__</span></code> special
attribute in your classes. If its set to (“x”, “y”), the following patterns are all
equivalent (and all bind the <code class="docutils literal notranslate"><span class="pre">y</span></code> attribute to the <code class="docutils literal notranslate"><span class="pre">var</span></code> variable):</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Point</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">var</span><span class="p">)</span>
<span class="n">Point</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">y</span><span class="o">=</span><span class="n">var</span><span class="p">)</span>
<span class="n">Point</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">y</span><span class="o">=</span><span class="n">var</span><span class="p">)</span>
<span class="n">Point</span><span class="p">(</span><span class="n">y</span><span class="o">=</span><span class="n">var</span><span class="p">,</span> <span class="n">x</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
</pre></div>
</div>
<p>Patterns can be arbitrarily nested. For example, if we have a short
list of points, we could match it like this:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">points</span><span class="p">:</span>
<span class="k">case</span> <span class="p">[]:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;No points&quot;</span><span class="p">)</span>
<span class="k">case</span> <span class="p">[</span><span class="n">Point</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">)]:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;The origin&quot;</span><span class="p">)</span>
<span class="k">case</span> <span class="p">[</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="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Single point </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>
<span class="k">case</span> <span class="p">[</span><span class="n">Point</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">y1</span><span class="p">),</span> <span class="n">Point</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">y2</span><span class="p">)]:</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Two on the Y axis at </span><span class="si">{</span><span class="n">y1</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">y2</span><span class="si">}</span><span class="s2">&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>We can add an <code class="docutils literal notranslate"><span class="pre">if</span></code> clause to a pattern, known as a “guard”. If the
guard is false, <code class="docutils literal notranslate"><span class="pre">match</span></code> goes on to try the next case block. Note
that value capture happens before the guard is evaluated:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">point</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="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="sa">f</span><span class="s2">&quot;Y=X at </span><span class="si">{</span><span class="n">x</span><span class="si">}</span><span class="s2">&quot;</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="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Not on the diagonal&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>Several other key features:</p>
<ul>
<li>Like unpacking assignments, tuple and list patterns have exactly the
same meaning and actually match arbitrary sequences. An important
exception is that they dont match iterators or strings.
(Technically, the subject must be an instance of
<code class="docutils literal notranslate"><span class="pre">collections.abc.Sequence</span></code>.)</li>
<li>Sequence patterns support wildcards: <code class="docutils literal notranslate"><span class="pre">[x,</span> <span class="pre">y,</span> <span class="pre">*rest]</span></code> and <code class="docutils literal notranslate"><span class="pre">(x,</span> <span class="pre">y,</span>
<span class="pre">*rest)</span></code> work similar to wildcards in unpacking assignments. The
name after <code class="docutils literal notranslate"><span class="pre">*</span></code> may also be <code class="docutils literal notranslate"><span class="pre">_</span></code>, so <code class="docutils literal notranslate"><span class="pre">(x,</span> <span class="pre">y,</span> <span class="pre">*_)</span></code> matches a sequence
of at least two items without binding the remaining items.</li>
<li>Mapping patterns: <code class="docutils literal notranslate"><span class="pre">{&quot;bandwidth&quot;:</span> <span class="pre">b,</span> <span class="pre">&quot;latency&quot;:</span> <span class="pre">l}</span></code> captures the
<code class="docutils literal notranslate"><span class="pre">&quot;bandwidth&quot;</span></code> and <code class="docutils literal notranslate"><span class="pre">&quot;latency&quot;</span></code> values from a dict. Unlike sequence
patterns, extra keys are ignored. A wildcard <code class="docutils literal notranslate"><span class="pre">**rest</span></code> is also
supported. (But <code class="docutils literal notranslate"><span class="pre">**_</span></code> would be redundant, so it is not allowed.)</li>
<li>Subpatterns may be captured using the <code class="docutils literal notranslate"><span class="pre">as</span></code> keyword:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">case</span> <span class="p">(</span><span class="n">Point</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">Point</span><span class="p">(</span><span class="n">x2</span><span class="p">,</span> <span class="n">y2</span><span class="p">)</span> <span class="k">as</span> <span class="n">p2</span><span class="p">):</span> <span class="o">...</span>
</pre></div>
</div>
</li>
<li>Most literals are compared by equality, however the singletons <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> are compared by identity.</li>
<li>Patterns may use named constants. These must be dotted names
to prevent them from being interpreted as capture variable:<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">Color</span><span class="p">(</span><span class="n">Enum</span><span class="p">):</span>
<span class="n">RED</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">GREEN</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">BLUE</span> <span class="o">=</span> <span class="mi">2</span>
<span class="k">match</span> <span class="n">color</span><span class="p">:</span>
<span class="k">case</span> <span class="n">Color</span><span class="o">.</span><span class="n">RED</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;I see red!&quot;</span><span class="p">)</span>
<span class="k">case</span> <span class="n">Color</span><span class="o">.</span><span class="n">GREEN</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Grass is green&quot;</span><span class="p">)</span>
<span class="k">case</span> <span class="n">Color</span><span class="o">.</span><span class="n">BLUE</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;I&#39;m feeling the blues :(&quot;</span><span class="p">)</span>
</pre></div>
</div>
</li>
</ul>
</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-0636.rst">https://github.com/python/peps/blob/main/peps/pep-0636.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0636.rst">2023-09-09 17:39:29 GMT</a></p>
</article>
<nav id="pep-sidebar">
<h2>Contents</h2>
<ul>
<li><a class="reference internal" href="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#tutorial">Tutorial</a><ul>
<li><a class="reference internal" href="#matching-sequences">Matching sequences</a></li>
<li><a class="reference internal" href="#matching-multiple-patterns">Matching multiple patterns</a></li>
<li><a class="reference internal" href="#matching-specific-values">Matching specific values</a></li>
<li><a class="reference internal" href="#matching-multiple-values">Matching multiple values</a></li>
<li><a class="reference internal" href="#adding-a-wildcard">Adding a wildcard</a></li>
<li><a class="reference internal" href="#composing-patterns">Composing patterns</a></li>
<li><a class="reference internal" href="#or-patterns">Or patterns</a></li>
<li><a class="reference internal" href="#capturing-matched-sub-patterns">Capturing matched sub-patterns</a></li>
<li><a class="reference internal" href="#adding-conditions-to-patterns">Adding conditions to patterns</a></li>
<li><a class="reference internal" href="#adding-a-ui-matching-objects">Adding a UI: Matching objects</a></li>
<li><a class="reference internal" href="#matching-positional-attributes">Matching positional attributes</a></li>
<li><a class="reference internal" href="#matching-against-constants-and-enums">Matching against constants and enums</a></li>
<li><a class="reference internal" href="#going-to-the-cloud-mappings">Going to the cloud: Mappings</a></li>
<li><a class="reference internal" href="#matching-builtin-classes">Matching builtin classes</a></li>
</ul>
</li>
<li><a class="reference internal" href="#appendix-a-quick-intro">Appendix A Quick Intro</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-0636.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>