peps/pep-0586/index.html

873 lines
89 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!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 586 Literal Types | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-0586/">
<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 586 Literal Types | peps.python.org'>
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-0586/">
<meta property="og:site_name" content="Python Enhancement Proposals (PEPs)">
<meta property="og:image" content="https://peps.python.org/_static/og-image.png">
<meta property="og:image:alt" content="Python PEPs">
<meta property="og:image:width" content="200">
<meta property="og:image:height" content="200">
<meta name="description" content="Python Enhancement Proposals (PEPs)">
<meta name="theme-color" content="#3776ab">
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all">
<title>Following system colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="9"></circle>
<path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path>
</svg>
</symbol>
<symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all">
<title>Selected dark colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path>
</svg>
</symbol>
<symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all">
<title>Selected light colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
</symbol>
</svg>
<script>
document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto"
</script>
<section id="pep-page-section">
<header>
<h1>Python Enhancement Proposals</h1>
<ul class="breadcrumbs">
<li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> &raquo; </li>
<li><a href="../pep-0000/">PEP Index</a> &raquo; </li>
<li>PEP 586</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 586 Literal Types</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Michael Lee &lt;michael.lee.0x2a&#32;&#97;t&#32;gmail.com&gt;, Ivan Levkivskyi &lt;levkivskyi&#32;&#97;t&#32;gmail.com&gt;, Jukka Lehtosalo &lt;jukka.lehtosalo&#32;&#97;t&#32;iki.fi&gt;</dd>
<dt class="field-even">BDFL-Delegate<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">Discussions-To<span class="colon">:</span></dt>
<dd class="field-odd"><a class="reference external" href="https://mail.python.org/archives/list/typing-sig&#64;python.org/">Typing-SIG list</a></dd>
<dt class="field-even">Status<span class="colon">:</span></dt>
<dd class="field-even"><abbr title="Accepted and implementation complete, or no longer active">Final</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">Topic<span class="colon">:</span></dt>
<dd class="field-even"><a class="reference external" href="../topic/typing/">Typing</a></dd>
<dt class="field-odd">Created<span class="colon">:</span></dt>
<dd class="field-odd">14-Mar-2019</dd>
<dt class="field-even">Python-Version<span class="colon">:</span></dt>
<dd class="field-even">3.8</dd>
<dt class="field-odd">Post-History<span class="colon">:</span></dt>
<dd class="field-odd">14-Mar-2019</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/typing-sig&#64;python.org/message/FDO4KFYWYQEP3U2HVVBEBR3SXPHQSHYR/">Typing-SIG 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="#motivation-and-rationale">Motivation and Rationale</a></li>
<li><a class="reference internal" href="#core-semantics">Core Semantics</a><ul>
<li><a class="reference internal" href="#core-behavior">Core behavior</a></li>
<li><a class="reference internal" href="#equivalence-of-two-literals">Equivalence of two Literals</a></li>
<li><a class="reference internal" href="#shortening-unions-of-literals">Shortening unions of literals</a></li>
</ul>
</li>
<li><a class="reference internal" href="#legal-and-illegal-parameterizations">Legal and illegal parameterizations</a><ul>
<li><a class="reference internal" href="#legal-parameters-for-literal-at-type-check-time">Legal parameters for <code class="docutils literal notranslate"><span class="pre">Literal</span></code> at type check time</a></li>
<li><a class="reference internal" href="#illegal-parameters-for-literal-at-type-check-time">Illegal parameters for <code class="docutils literal notranslate"><span class="pre">Literal</span></code> at type check time</a></li>
<li><a class="reference internal" href="#parameters-at-runtime">Parameters at runtime</a></li>
<li><a class="reference internal" href="#literals-enums-and-forward-references">Literals, enums, and forward references</a></li>
</ul>
</li>
<li><a class="reference internal" href="#type-inference">Type inference</a><ul>
<li><a class="reference internal" href="#backwards-compatibility">Backwards compatibility</a></li>
<li><a class="reference internal" href="#using-non-literals-in-literal-contexts">Using non-Literals in Literal contexts</a></li>
</ul>
</li>
<li><a class="reference internal" href="#interactions-with-other-types-and-features">Interactions with other types and features</a><ul>
<li><a class="reference internal" href="#intelligent-indexing-of-structured-data">Intelligent indexing of structured data</a></li>
<li><a class="reference internal" href="#interactions-with-overloads">Interactions with overloads</a></li>
<li><a class="reference internal" href="#interactions-with-generics">Interactions with generics</a></li>
<li><a class="reference internal" href="#interactions-with-enums-and-exhaustiveness-checks">Interactions with enums and exhaustiveness checks</a></li>
<li><a class="reference internal" href="#interactions-with-narrowing">Interactions with narrowing</a></li>
<li><a class="reference internal" href="#interactions-with-final">Interactions with Final</a></li>
</ul>
</li>
<li><a class="reference internal" href="#rejected-or-out-of-scope-ideas">Rejected or out-of-scope ideas</a><ul>
<li><a class="reference internal" href="#true-dependent-types-integer-generics">True dependent types/integer generics</a></li>
<li><a class="reference internal" href="#adding-more-concise-syntax">Adding more concise syntax</a></li>
</ul>
</li>
<li><a class="reference internal" href="#backporting-the-literal-type">Backporting the <code class="docutils literal notranslate"><span class="pre">Literal</span></code> type</a></li>
<li><a class="reference internal" href="#implementation">Implementation</a></li>
<li><a class="reference internal" href="#related-work">Related work</a></li>
<li><a class="reference internal" href="#acknowledgements">Acknowledgements</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
</details></section>
<div class="pep-banner canonical-typing-spec sticky-banner admonition attention">
<p class="admonition-title">Attention</p>
<p>This PEP is a historical document. The up-to-date, canonical spec, <a class="reference external" href="https://typing.readthedocs.io/en/latest/spec/literal.html#literal-types" title="(in typing)"><span>Literals</span></a>, is maintained on the <a class="reference external" href="https://typing.readthedocs.io/en/latest/spec/">typing specs site</a>.</p>
<p class="close-button">×</p>
<p>See the <a class="reference external" href="https://typing.readthedocs.io/en/latest/spec/meta.html">typing specification update process</a> for how to propose changes.</p>
</div>
<section id="abstract">
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
<p>This PEP proposes adding <em>Literal types</em> to the <a class="pep reference internal" href="../pep-0484/" title="PEP 484 Type Hints">PEP 484</a> ecosystem.
Literal types indicate that some expression has literally a
specific value. For example, the following function will accept
only expressions that have literally the value “4”:</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">Literal</span>
<span class="k">def</span> <span class="nf">accepts_only_four</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="mi">4</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">pass</span>
<span class="n">accepts_only_four</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span> <span class="c1"># OK</span>
<span class="n">accepts_only_four</span><span class="p">(</span><span class="mi">19</span><span class="p">)</span> <span class="c1"># Rejected</span>
</pre></div>
</div>
</section>
<section id="motivation-and-rationale">
<h2><a class="toc-backref" href="#motivation-and-rationale" role="doc-backlink">Motivation and Rationale</a></h2>
<p>Python has many APIs that return different types depending on the
value of some argument provided. For example:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">open(filename,</span> <span class="pre">mode)</span></code> returns either <code class="docutils literal notranslate"><span class="pre">IO[bytes]</span></code> or <code class="docutils literal notranslate"><span class="pre">IO[Text]</span></code>
depending on whether the second argument is something like <code class="docutils literal notranslate"><span class="pre">r</span></code> or
<code class="docutils literal notranslate"><span class="pre">rb</span></code>.</li>
<li><code class="docutils literal notranslate"><span class="pre">subprocess.check_output(...)</span></code> returns either bytes or text
depending on whether the <code class="docutils literal notranslate"><span class="pre">universal_newlines</span></code> keyword argument is
set to <code class="docutils literal notranslate"><span class="pre">True</span></code> or not.</li>
</ul>
<p>This pattern is also fairly common in many popular 3rd party libraries.
For example, here are just two examples from pandas and numpy respectively:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">pandas.concat(...)</span></code> will return either <code class="docutils literal notranslate"><span class="pre">Series</span></code> or
<code class="docutils literal notranslate"><span class="pre">DataFrame</span></code> depending on whether the <code class="docutils literal notranslate"><span class="pre">axis</span></code> argument is set to
0 or 1.</li>
<li><code class="docutils literal notranslate"><span class="pre">numpy.unique</span></code> will return either a single array or a tuple containing
anywhere from two to four arrays depending on three boolean flag values.</li>
</ul>
<p>The typing issue tracker contains some
<a class="reference external" href="https://github.com/python/typing/issues/478">additional examples and discussion</a>.</p>
<p>There is currently no way of expressing the type signatures of these
functions: <a class="pep reference internal" href="../pep-0484/" title="PEP 484 Type Hints">PEP 484</a> does not include any mechanism for writing signatures
where the return type varies depending on the value passed in.
Note that this problem persists even if we redesign these APIs to
instead accept enums: <code class="docutils literal notranslate"><span class="pre">MyEnum.FOO</span></code> and <code class="docutils literal notranslate"><span class="pre">MyEnum.BAR</span></code> are both
considered to be of type <code class="docutils literal notranslate"><span class="pre">MyEnum</span></code>.</p>
<p>Currently, type checkers work around this limitation by adding ad hoc
extensions for important builtins and standard library functions. For
example, mypy comes bundled with a plugin that attempts to infer more
precise types for <code class="docutils literal notranslate"><span class="pre">open(...)</span></code>. While this approach works for standard
library functions, its unsustainable in general: its not reasonable to
expect 3rd party library authors to maintain plugins for N different
type checkers.</p>
<p>We propose adding <em>Literal types</em> to address these gaps.</p>
</section>
<section id="core-semantics">
<h2><a class="toc-backref" href="#core-semantics" role="doc-backlink">Core Semantics</a></h2>
<p>This section outlines the baseline behavior of literal types.</p>
<section id="core-behavior">
<h3><a class="toc-backref" href="#core-behavior" role="doc-backlink">Core behavior</a></h3>
<p>Literal types indicate that a variable has a specific and
concrete value. For example, if we define some variable <code class="docutils literal notranslate"><span class="pre">foo</span></code> to have
type <code class="docutils literal notranslate"><span class="pre">Literal[3]</span></code>, we are declaring that <code class="docutils literal notranslate"><span class="pre">foo</span></code> must be exactly equal
to <code class="docutils literal notranslate"><span class="pre">3</span></code> and no other value.</p>
<p>Given some value <code class="docutils literal notranslate"><span class="pre">v</span></code> that is a member of type <code class="docutils literal notranslate"><span class="pre">T</span></code>, the type
<code class="docutils literal notranslate"><span class="pre">Literal[v]</span></code> shall be treated as a subtype of <code class="docutils literal notranslate"><span class="pre">T</span></code>. For example,
<code class="docutils literal notranslate"><span class="pre">Literal[3]</span></code> is a subtype of <code class="docutils literal notranslate"><span class="pre">int</span></code>.</p>
<p>All methods from the parent type will be directly inherited by the
literal type. So, if we have some variable <code class="docutils literal notranslate"><span class="pre">foo</span></code> of type <code class="docutils literal notranslate"><span class="pre">Literal[3]</span></code>
its safe to do things like <code class="docutils literal notranslate"><span class="pre">foo</span> <span class="pre">+</span> <span class="pre">5</span></code> since <code class="docutils literal notranslate"><span class="pre">foo</span></code> inherits ints
<code class="docutils literal notranslate"><span class="pre">__add__</span></code> method. The resulting type of <code class="docutils literal notranslate"><span class="pre">foo</span> <span class="pre">+</span> <span class="pre">5</span></code> is <code class="docutils literal notranslate"><span class="pre">int</span></code>.</p>
<p>This “inheriting” behavior is identical to how we
<a class="pep reference internal" href="../pep-0484/#newtype-helper-function" title="PEP 484 Type Hints § NewType helper function">handle NewTypes</a>.</p>
</section>
<section id="equivalence-of-two-literals">
<h3><a class="toc-backref" href="#equivalence-of-two-literals" role="doc-backlink">Equivalence of two Literals</a></h3>
<p>Two types <code class="docutils literal notranslate"><span class="pre">Literal[v1]</span></code> and <code class="docutils literal notranslate"><span class="pre">Literal[v2]</span></code> are equivalent when
both of the following conditions are true:</p>
<ol class="arabic simple">
<li><code class="docutils literal notranslate"><span class="pre">type(v1)</span> <span class="pre">==</span> <span class="pre">type(v2)</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">v1</span> <span class="pre">==</span> <span class="pre">v2</span></code></li>
</ol>
<p>For example, <code class="docutils literal notranslate"><span class="pre">Literal[20]</span></code> and <code class="docutils literal notranslate"><span class="pre">Literal[0x14]</span></code> are equivalent.
However, <code class="docutils literal notranslate"><span class="pre">Literal[0]</span></code> and <code class="docutils literal notranslate"><span class="pre">Literal[False]</span></code> is <em>not</em> equivalent
despite that <code class="docutils literal notranslate"><span class="pre">0</span> <span class="pre">==</span> <span class="pre">False</span></code> evaluates to true at runtime: <code class="docutils literal notranslate"><span class="pre">0</span></code>
has type <code class="docutils literal notranslate"><span class="pre">int</span></code> and <code class="docutils literal notranslate"><span class="pre">False</span></code> has type <code class="docutils literal notranslate"><span class="pre">bool</span></code>.</p>
</section>
<section id="shortening-unions-of-literals">
<h3><a class="toc-backref" href="#shortening-unions-of-literals" role="doc-backlink">Shortening unions of literals</a></h3>
<p>Literals are parameterized with one or more values. When a Literal is
parameterized with more than one value, its treated as exactly equivalent
to the union of those types. That is, <code class="docutils literal notranslate"><span class="pre">Literal[v1,</span> <span class="pre">v2,</span> <span class="pre">v3]</span></code> is equivalent
to <code class="docutils literal notranslate"><span class="pre">Union[Literal[v1],</span> <span class="pre">Literal[v2],</span> <span class="pre">Literal[v3]]</span></code>.</p>
<p>This shortcut helps make writing signatures for functions that accept
many different literals more ergonomic — for example, functions like
<code class="docutils literal notranslate"><span class="pre">open(...)</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Note: this is a simplification of the true type signature.</span>
<span class="n">_PathType</span> <span class="o">=</span> <span class="n">Union</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">,</span> <span class="nb">int</span><span class="p">]</span>
<span class="nd">@overload</span>
<span class="k">def</span> <span class="nf">open</span><span class="p">(</span><span class="n">path</span><span class="p">:</span> <span class="n">_PathType</span><span class="p">,</span>
<span class="n">mode</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="s2">&quot;r&quot;</span><span class="p">,</span> <span class="s2">&quot;w&quot;</span><span class="p">,</span> <span class="s2">&quot;a&quot;</span><span class="p">,</span> <span class="s2">&quot;x&quot;</span><span class="p">,</span> <span class="s2">&quot;r+&quot;</span><span class="p">,</span> <span class="s2">&quot;w+&quot;</span><span class="p">,</span> <span class="s2">&quot;a+&quot;</span><span class="p">,</span> <span class="s2">&quot;x+&quot;</span><span class="p">],</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="n">IO</span><span class="p">[</span><span class="n">Text</span><span class="p">]:</span> <span class="o">...</span>
<span class="nd">@overload</span>
<span class="k">def</span> <span class="nf">open</span><span class="p">(</span><span class="n">path</span><span class="p">:</span> <span class="n">_PathType</span><span class="p">,</span>
<span class="n">mode</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="s2">&quot;rb&quot;</span><span class="p">,</span> <span class="s2">&quot;wb&quot;</span><span class="p">,</span> <span class="s2">&quot;ab&quot;</span><span class="p">,</span> <span class="s2">&quot;xb&quot;</span><span class="p">,</span> <span class="s2">&quot;r+b&quot;</span><span class="p">,</span> <span class="s2">&quot;w+b&quot;</span><span class="p">,</span> <span class="s2">&quot;a+b&quot;</span><span class="p">,</span> <span class="s2">&quot;x+b&quot;</span><span class="p">],</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="n">IO</span><span class="p">[</span><span class="nb">bytes</span><span class="p">]:</span> <span class="o">...</span>
<span class="c1"># Fallback overload for when the user isn&#39;t using literal types</span>
<span class="nd">@overload</span>
<span class="k">def</span> <span class="nf">open</span><span class="p">(</span><span class="n">path</span><span class="p">:</span> <span class="n">_PathType</span><span class="p">,</span> <span class="n">mode</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">IO</span><span class="p">[</span><span class="n">Any</span><span class="p">]:</span> <span class="o">...</span>
</pre></div>
</div>
<p>The provided values do not all have to be members of the same type.
For example, <code class="docutils literal notranslate"><span class="pre">Literal[42,</span> <span class="pre">&quot;foo&quot;,</span> <span class="pre">True]</span></code> is a legal type.</p>
<p>However, Literal <strong>must</strong> be parameterized with at least one type.
Types like <code class="docutils literal notranslate"><span class="pre">Literal[]</span></code> or <code class="docutils literal notranslate"><span class="pre">Literal</span></code> are illegal.</p>
</section>
</section>
<section id="legal-and-illegal-parameterizations">
<h2><a class="toc-backref" href="#legal-and-illegal-parameterizations" role="doc-backlink">Legal and illegal parameterizations</a></h2>
<p>This section describes what exactly constitutes a legal <code class="docutils literal notranslate"><span class="pre">Literal[...]</span></code> type:
what values may and may not be used as parameters.</p>
<p>In short, a <code class="docutils literal notranslate"><span class="pre">Literal[...]</span></code> type may be parameterized by one or more literal
expressions, and nothing else.</p>
<section id="legal-parameters-for-literal-at-type-check-time">
<h3><a class="toc-backref" href="#legal-parameters-for-literal-at-type-check-time" role="doc-backlink">Legal parameters for <code class="docutils literal notranslate"><span class="pre">Literal</span></code> at type check time</a></h3>
<p><code class="docutils literal notranslate"><span class="pre">Literal</span></code> may be parameterized with literal ints, byte and unicode strings,
bools, Enum values and <code class="docutils literal notranslate"><span class="pre">None</span></code>. So for example, all of
the following would be legal:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Literal</span><span class="p">[</span><span class="mi">26</span><span class="p">]</span>
<span class="n">Literal</span><span class="p">[</span><span class="mh">0x1A</span><span class="p">]</span> <span class="c1"># Exactly equivalent to Literal[26]</span>
<span class="n">Literal</span><span class="p">[</span><span class="o">-</span><span class="mi">4</span><span class="p">]</span>
<span class="n">Literal</span><span class="p">[</span><span class="s2">&quot;hello world&quot;</span><span class="p">]</span>
<span class="n">Literal</span><span class="p">[</span><span class="sa">b</span><span class="s2">&quot;hello world&quot;</span><span class="p">]</span>
<span class="n">Literal</span><span class="p">[</span><span class="sa">u</span><span class="s2">&quot;hello world&quot;</span><span class="p">]</span>
<span class="n">Literal</span><span class="p">[</span><span class="kc">True</span><span class="p">]</span>
<span class="n">Literal</span><span class="p">[</span><span class="n">Color</span><span class="o">.</span><span class="n">RED</span><span class="p">]</span> <span class="c1"># Assuming Color is some enum</span>
<span class="n">Literal</span><span class="p">[</span><span class="kc">None</span><span class="p">]</span>
</pre></div>
</div>
<p><strong>Note:</strong> Since the type <code class="docutils literal notranslate"><span class="pre">None</span></code> is inhabited by just a single
value, the types <code class="docutils literal notranslate"><span class="pre">None</span></code> and <code class="docutils literal notranslate"><span class="pre">Literal[None]</span></code> are exactly equivalent.
Type checkers may simplify <code class="docutils literal notranslate"><span class="pre">Literal[None]</span></code> into just <code class="docutils literal notranslate"><span class="pre">None</span></code>.</p>
<p><code class="docutils literal notranslate"><span class="pre">Literal</span></code> may also be parameterized by other literal types, or type aliases
to other literal types. For example, the following is legal:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">ReadOnlyMode</span> <span class="o">=</span> <span class="n">Literal</span><span class="p">[</span><span class="s2">&quot;r&quot;</span><span class="p">,</span> <span class="s2">&quot;r+&quot;</span><span class="p">]</span>
<span class="n">WriteAndTruncateMode</span> <span class="o">=</span> <span class="n">Literal</span><span class="p">[</span><span class="s2">&quot;w&quot;</span><span class="p">,</span> <span class="s2">&quot;w+&quot;</span><span class="p">,</span> <span class="s2">&quot;wt&quot;</span><span class="p">,</span> <span class="s2">&quot;w+t&quot;</span><span class="p">]</span>
<span class="n">WriteNoTruncateMode</span> <span class="o">=</span> <span class="n">Literal</span><span class="p">[</span><span class="s2">&quot;r+&quot;</span><span class="p">,</span> <span class="s2">&quot;r+t&quot;</span><span class="p">]</span>
<span class="n">AppendMode</span> <span class="o">=</span> <span class="n">Literal</span><span class="p">[</span><span class="s2">&quot;a&quot;</span><span class="p">,</span> <span class="s2">&quot;a+&quot;</span><span class="p">,</span> <span class="s2">&quot;at&quot;</span><span class="p">,</span> <span class="s2">&quot;a+t&quot;</span><span class="p">]</span>
<span class="n">AllModes</span> <span class="o">=</span> <span class="n">Literal</span><span class="p">[</span><span class="n">ReadOnlyMode</span><span class="p">,</span> <span class="n">WriteAndTruncateMode</span><span class="p">,</span>
<span class="n">WriteNoTruncateMode</span><span class="p">,</span> <span class="n">AppendMode</span><span class="p">]</span>
</pre></div>
</div>
<p>This feature is again intended to help make using and reusing literal types
more ergonomic.</p>
<p><strong>Note:</strong> As a consequence of the above rules, type checkers are also expected
to support types that look like the following:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Literal</span><span class="p">[</span><span class="n">Literal</span><span class="p">[</span><span class="n">Literal</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">],</span> <span class="s2">&quot;foo&quot;</span><span class="p">],</span> <span class="mi">5</span><span class="p">,</span> <span class="kc">None</span><span class="p">]</span>
</pre></div>
</div>
<p>This should be exactly equivalent to the following type:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Literal</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="s2">&quot;foo&quot;</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="kc">None</span><span class="p">]</span>
</pre></div>
</div>
<p>…and also to the following type:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Optional</span><span class="p">[</span><span class="n">Literal</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="s2">&quot;foo&quot;</span><span class="p">,</span> <span class="mi">5</span><span class="p">]]</span>
</pre></div>
</div>
<p><strong>Note:</strong> String literal types like <code class="docutils literal notranslate"><span class="pre">Literal[&quot;foo&quot;]</span></code> should subtype either
bytes or unicode in the same way regular string literals do at runtime.</p>
<p>For example, in Python 3, the type <code class="docutils literal notranslate"><span class="pre">Literal[&quot;foo&quot;]</span></code> is equivalent to
<code class="docutils literal notranslate"><span class="pre">Literal[u&quot;foo&quot;]</span></code>, since <code class="docutils literal notranslate"><span class="pre">&quot;foo&quot;</span></code> is equivalent to <code class="docutils literal notranslate"><span class="pre">u&quot;foo&quot;</span></code> in Python 3.</p>
<p>Similarly, in Python 2, the type <code class="docutils literal notranslate"><span class="pre">Literal[&quot;foo&quot;]</span></code> is equivalent to
<code class="docutils literal notranslate"><span class="pre">Literal[b&quot;foo&quot;]</span></code> unless the file includes a
<code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">__future__</span> <span class="pre">import</span> <span class="pre">unicode_literals</span></code> import, in which case it would be
equivalent to <code class="docutils literal notranslate"><span class="pre">Literal[u&quot;foo&quot;]</span></code>.</p>
</section>
<section id="illegal-parameters-for-literal-at-type-check-time">
<h3><a class="toc-backref" href="#illegal-parameters-for-literal-at-type-check-time" role="doc-backlink">Illegal parameters for <code class="docutils literal notranslate"><span class="pre">Literal</span></code> at type check time</a></h3>
<p>The following parameters are intentionally disallowed by design:</p>
<ul class="simple">
<li>Arbitrary expressions like <code class="docutils literal notranslate"><span class="pre">Literal[3</span> <span class="pre">+</span> <span class="pre">4]</span></code> or
<code class="docutils literal notranslate"><span class="pre">Literal[&quot;foo&quot;.replace(&quot;o&quot;,</span> <span class="pre">&quot;b&quot;)]</span></code>.<ul>
<li>Rationale: Literal types are meant to be a
minimal extension to the <a class="pep reference internal" href="../pep-0484/" title="PEP 484 Type Hints">PEP 484</a> typing ecosystem and requiring type
checkers to interpret potentially expressions inside types adds too
much complexity. Also see <a class="reference internal" href="#rejected-or-out-of-scope-ideas">Rejected or out-of-scope ideas</a>.</li>
<li>As a consequence, complex numbers like <code class="docutils literal notranslate"><span class="pre">Literal[4</span> <span class="pre">+</span> <span class="pre">3j]</span></code> and
<code class="docutils literal notranslate"><span class="pre">Literal[-4</span> <span class="pre">+</span> <span class="pre">2j]</span></code> are also prohibited. For consistency, literals like
<code class="docutils literal notranslate"><span class="pre">Literal[4j]</span></code> that contain just a single complex number are also
prohibited.</li>
<li>The only exception to this rule is the unary <code class="docutils literal notranslate"><span class="pre">-</span></code> (minus) for ints: types
like <code class="docutils literal notranslate"><span class="pre">Literal[-5]</span></code> are <em>accepted</em>.</li>
</ul>
</li>
<li>Tuples containing valid literal types like <code class="docutils literal notranslate"><span class="pre">Literal[(1,</span> <span class="pre">&quot;foo&quot;,</span> <span class="pre">&quot;bar&quot;)]</span></code>.
The user could always express this type as
<code class="docutils literal notranslate"><span class="pre">Tuple[Literal[1],</span> <span class="pre">Literal[&quot;foo&quot;],</span> <span class="pre">Literal[&quot;bar&quot;]]</span></code> instead. Also,
tuples are likely to be confused with the <code class="docutils literal notranslate"><span class="pre">Literal[1,</span> <span class="pre">2,</span> <span class="pre">3]</span></code>
shortcut.</li>
<li>Mutable literal data structures like dict literals, list literals, or
set literals: literals are always implicitly final and immutable. So,
<code class="docutils literal notranslate"><span class="pre">Literal[{&quot;a&quot;:</span> <span class="pre">&quot;b&quot;,</span> <span class="pre">&quot;c&quot;:</span> <span class="pre">&quot;d&quot;}]</span></code> is illegal.</li>
<li>Any other types: for example, <code class="docutils literal notranslate"><span class="pre">Literal[Path]</span></code>, or
<code class="docutils literal notranslate"><span class="pre">Literal[some_object_instance]</span></code> are illegal. This includes typevars: if
<code class="docutils literal notranslate"><span class="pre">T</span></code> is a typevar, <code class="docutils literal notranslate"><span class="pre">Literal[T]</span></code> is not allowed. Typevars can vary over
only types, never over values.</li>
</ul>
<p>The following are provisionally disallowed for simplicity. We can consider
allowing them in future extensions of this PEP.</p>
<ul class="simple">
<li>Floats: e.g. <code class="docutils literal notranslate"><span class="pre">Literal[3.14]</span></code>. Representing Literals of infinity or NaN
in a clean way is tricky; real-world APIs are unlikely to vary their
behavior based on a float parameter.</li>
<li>Any: e.g. <code class="docutils literal notranslate"><span class="pre">Literal[Any]</span></code>. <code class="docutils literal notranslate"><span class="pre">Any</span></code> is a type, and <code class="docutils literal notranslate"><span class="pre">Literal[...]</span></code> is
meant to contain values only. It is also unclear what <code class="docutils literal notranslate"><span class="pre">Literal[Any]</span></code>
would actually semantically mean.</li>
</ul>
</section>
<section id="parameters-at-runtime">
<h3><a class="toc-backref" href="#parameters-at-runtime" role="doc-backlink">Parameters at runtime</a></h3>
<p>Although the set of parameters <code class="docutils literal notranslate"><span class="pre">Literal[...]</span></code> may contain at type check time
is very small, the actual implementation of <code class="docutils literal notranslate"><span class="pre">typing.Literal</span></code> will not perform
any checks at runtime. For example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">my_function</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="mi">1</span> <span class="o">+</span> <span class="mi">2</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="k">return</span> <span class="n">x</span> <span class="o">*</span> <span class="mi">3</span>
<span class="n">x</span><span class="p">:</span> <span class="n">Literal</span> <span class="o">=</span> <span class="mi">3</span>
<span class="n">y</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="n">my_function</span><span class="p">]</span> <span class="o">=</span> <span class="n">my_function</span>
</pre></div>
</div>
<p>The type checker should reject this program: all three uses of
<code class="docutils literal notranslate"><span class="pre">Literal</span></code> are <em>invalid</em> according to this spec. However, Python itself
should execute this program with no errors.</p>
<p>This is partly to help us preserve flexibility in case we want to expand the
scope of what <code class="docutils literal notranslate"><span class="pre">Literal</span></code> can be used for in the future, and partly because
it is not possible to detect all illegal parameters at runtime to begin with.
For example, it is impossible to distinguish between <code class="docutils literal notranslate"><span class="pre">Literal[1</span> <span class="pre">+</span> <span class="pre">2]</span></code> and
<code class="docutils literal notranslate"><span class="pre">Literal[3]</span></code> at runtime.</p>
</section>
<section id="literals-enums-and-forward-references">
<h3><a class="toc-backref" href="#literals-enums-and-forward-references" role="doc-backlink">Literals, enums, and forward references</a></h3>
<p>One potential ambiguity is between literal strings and forward
references to literal enum members. For example, suppose we have the
type <code class="docutils literal notranslate"><span class="pre">Literal[&quot;Color.RED&quot;]</span></code>. Does this literal type
contain a string literal or a forward reference to some <code class="docutils literal notranslate"><span class="pre">Color.RED</span></code>
enum member?</p>
<p>In cases like these, we always assume the user meant to construct a
literal string. If the user wants a forward reference, they must wrap
the entire literal type in a string e.g. <code class="docutils literal notranslate"><span class="pre">&quot;Literal[Color.RED]&quot;</span></code>.</p>
</section>
</section>
<section id="type-inference">
<h2><a class="toc-backref" href="#type-inference" role="doc-backlink">Type inference</a></h2>
<p>This section describes a few rules regarding type inference and
literals, along with some examples.</p>
<section id="backwards-compatibility">
<h3><a class="toc-backref" href="#backwards-compatibility" role="doc-backlink">Backwards compatibility</a></h3>
<p>When type checkers add support for Literal, its important they do so
in a way that maximizes backwards-compatibility. Type checkers should
ensure that code that used to type check continues to do so after support
for Literal is added on a best-effort basis.</p>
<p>This is particularly important when performing type inference. For
example, given the statement <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">=</span> <span class="pre">&quot;blue&quot;</span></code>, should the inferred
type of <code class="docutils literal notranslate"><span class="pre">x</span></code> be <code class="docutils literal notranslate"><span class="pre">str</span></code> or <code class="docutils literal notranslate"><span class="pre">Literal[&quot;blue&quot;]</span></code>?</p>
<p>One naive strategy would be to always assume expressions are intended
to be Literal types. So, <code class="docutils literal notranslate"><span class="pre">x</span></code> would always have an inferred type of
<code class="docutils literal notranslate"><span class="pre">Literal[&quot;blue&quot;]</span></code> in the example above. This naive strategy is almost
certainly too disruptive it would cause programs like the following
to start failing when they previously did not:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># If a type checker infers &#39;var&#39; has type Literal[3]</span>
<span class="c1"># and my_list has type List[Literal[3]]...</span>
<span class="n">var</span> <span class="o">=</span> <span class="mi">3</span>
<span class="n">my_list</span> <span class="o">=</span> <span class="p">[</span><span class="n">var</span><span class="p">]</span>
<span class="c1"># ...this call would be a type-error.</span>
<span class="n">my_list</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
</pre></div>
</div>
<p>Another example of when this strategy would fail is when setting fields
in objects:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">MyObject</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="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="c1"># If a type checker infers MyObject.field has type Literal[3]...</span>
<span class="bp">self</span><span class="o">.</span><span class="n">field</span> <span class="o">=</span> <span class="mi">3</span>
<span class="n">m</span> <span class="o">=</span> <span class="n">MyObject</span><span class="p">()</span>
<span class="c1"># ...this assignment would no longer type check</span>
<span class="n">m</span><span class="o">.</span><span class="n">field</span> <span class="o">=</span> <span class="mi">4</span>
</pre></div>
</div>
<p>An alternative strategy that <em>does</em> maintain compatibility in every case would
be to always assume expressions are <em>not</em> Literal types unless they are
explicitly annotated otherwise. A type checker using this strategy would
always infer that <code class="docutils literal notranslate"><span class="pre">x</span></code> is of type <code class="docutils literal notranslate"><span class="pre">str</span></code> in the first example above.</p>
<p>This is not the only viable strategy: type checkers should feel free to experiment
with more sophisticated inference techniques. This PEP does not mandate any
particular strategy; it only emphasizes the importance of backwards compatibility.</p>
</section>
<section id="using-non-literals-in-literal-contexts">
<h3><a class="toc-backref" href="#using-non-literals-in-literal-contexts" role="doc-backlink">Using non-Literals in Literal contexts</a></h3>
<p>Literal types follow the existing rules regarding subtyping with no additional
special-casing. For example, programs like the following are type safe:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">expects_str</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span> <span class="o">...</span>
<span class="n">var</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="s2">&quot;foo&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;foo&quot;</span>
<span class="c1"># Legal: Literal[&quot;foo&quot;] is a subtype of str</span>
<span class="n">expects_str</span><span class="p">(</span><span class="n">var</span><span class="p">)</span>
</pre></div>
</div>
<p>This also means non-Literal expressions in general should not automatically
be cast to Literal. For example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">expects_literal</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="s2">&quot;foo&quot;</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span> <span class="o">...</span>
<span class="k">def</span> <span class="nf">runner</span><span class="p">(</span><span class="n">my_str</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="c1"># ILLEGAL: str is not a subclass of Literal[&quot;foo&quot;]</span>
<span class="n">expects_literal</span><span class="p">(</span><span class="n">my_str</span><span class="p">)</span>
</pre></div>
</div>
<p><strong>Note:</strong> If the user wants their API to support accepting both literals
<em>and</em> the original type perhaps for legacy purposes they should
implement a fallback overload. See <a class="reference internal" href="#interactions-with-overloads">Interactions with overloads</a>.</p>
</section>
</section>
<section id="interactions-with-other-types-and-features">
<h2><a class="toc-backref" href="#interactions-with-other-types-and-features" role="doc-backlink">Interactions with other types and features</a></h2>
<p>This section discusses how Literal types interact with other existing types.</p>
<section id="intelligent-indexing-of-structured-data">
<h3><a class="toc-backref" href="#intelligent-indexing-of-structured-data" role="doc-backlink">Intelligent indexing of structured data</a></h3>
<p>Literals can be used to “intelligently index” into structured types like
tuples, NamedTuple, and classes. (Note: this is not an exhaustive list).</p>
<p>For example, type checkers should infer the correct value type when
indexing into a tuple using an int key that corresponds a valid index:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">a</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">b</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="mi">5</span><span class="p">]</span> <span class="o">=</span> <span class="mi">5</span>
<span class="n">some_tuple</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="n">List</span><span class="p">[</span><span class="nb">bool</span><span class="p">]]</span> <span class="o">=</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="s2">&quot;abc&quot;</span><span class="p">,</span> <span class="p">[</span><span class="kc">True</span><span class="p">,</span> <span class="kc">False</span><span class="p">])</span>
<span class="n">reveal_type</span><span class="p">(</span><span class="n">some_tuple</span><span class="p">[</span><span class="n">a</span><span class="p">])</span> <span class="c1"># Revealed type is &#39;int&#39;</span>
<span class="n">some_tuple</span><span class="p">[</span><span class="n">b</span><span class="p">]</span> <span class="c1"># Error: 5 is not a valid index into the tuple</span>
</pre></div>
</div>
<p>We expect similar behavior when using functions like getattr:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Test</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">param</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">myfield</span> <span class="o">=</span> <span class="n">param</span>
<span class="k">def</span> <span class="nf">mymethod</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">val</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="o">...</span>
<span class="n">a</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="s2">&quot;myfield&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;myfield&quot;</span>
<span class="n">b</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="s2">&quot;mymethod&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;mymethod&quot;</span>
<span class="n">c</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="s2">&quot;blah&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;blah&quot;</span>
<span class="n">t</span> <span class="o">=</span> <span class="n">Test</span><span class="p">()</span>
<span class="n">reveal_type</span><span class="p">(</span><span class="nb">getattr</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">a</span><span class="p">))</span> <span class="c1"># Revealed type is &#39;int&#39;</span>
<span class="n">reveal_type</span><span class="p">(</span><span class="nb">getattr</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">b</span><span class="p">))</span> <span class="c1"># Revealed type is &#39;Callable[[int], str]&#39;</span>
<span class="nb">getattr</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">c</span><span class="p">)</span> <span class="c1"># Error: No attribute named &#39;blah&#39; in Test</span>
</pre></div>
</div>
<p><strong>Note:</strong> See <a class="reference internal" href="#interactions-with-final">Interactions with Final</a> for a proposal on how we can
express the variable declarations above in a more compact manner.</p>
</section>
<section id="interactions-with-overloads">
<h3><a class="toc-backref" href="#interactions-with-overloads" role="doc-backlink">Interactions with overloads</a></h3>
<p>Literal types and overloads do not need to interact in a special
way: the existing rules work fine.</p>
<p>However, one important use case type checkers must take care to
support is the ability to use a <em>fallback</em> when the user is not using literal
types. For example, consider <code class="docutils literal notranslate"><span class="pre">open</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">_PathType</span> <span class="o">=</span> <span class="n">Union</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">,</span> <span class="nb">int</span><span class="p">]</span>
<span class="nd">@overload</span>
<span class="k">def</span> <span class="nf">open</span><span class="p">(</span><span class="n">path</span><span class="p">:</span> <span class="n">_PathType</span><span class="p">,</span>
<span class="n">mode</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="s2">&quot;r&quot;</span><span class="p">,</span> <span class="s2">&quot;w&quot;</span><span class="p">,</span> <span class="s2">&quot;a&quot;</span><span class="p">,</span> <span class="s2">&quot;x&quot;</span><span class="p">,</span> <span class="s2">&quot;r+&quot;</span><span class="p">,</span> <span class="s2">&quot;w+&quot;</span><span class="p">,</span> <span class="s2">&quot;a+&quot;</span><span class="p">,</span> <span class="s2">&quot;x+&quot;</span><span class="p">],</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="n">IO</span><span class="p">[</span><span class="n">Text</span><span class="p">]:</span> <span class="o">...</span>
<span class="nd">@overload</span>
<span class="k">def</span> <span class="nf">open</span><span class="p">(</span><span class="n">path</span><span class="p">:</span> <span class="n">_PathType</span><span class="p">,</span>
<span class="n">mode</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="s2">&quot;rb&quot;</span><span class="p">,</span> <span class="s2">&quot;wb&quot;</span><span class="p">,</span> <span class="s2">&quot;ab&quot;</span><span class="p">,</span> <span class="s2">&quot;xb&quot;</span><span class="p">,</span> <span class="s2">&quot;r+b&quot;</span><span class="p">,</span> <span class="s2">&quot;w+b&quot;</span><span class="p">,</span> <span class="s2">&quot;a+b&quot;</span><span class="p">,</span> <span class="s2">&quot;x+b&quot;</span><span class="p">],</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="n">IO</span><span class="p">[</span><span class="nb">bytes</span><span class="p">]:</span> <span class="o">...</span>
<span class="c1"># Fallback overload for when the user isn&#39;t using literal types</span>
<span class="nd">@overload</span>
<span class="k">def</span> <span class="nf">open</span><span class="p">(</span><span class="n">path</span><span class="p">:</span> <span class="n">_PathType</span><span class="p">,</span> <span class="n">mode</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">IO</span><span class="p">[</span><span class="n">Any</span><span class="p">]:</span> <span class="o">...</span>
</pre></div>
</div>
<p>If we were to change the signature of <code class="docutils literal notranslate"><span class="pre">open</span></code> to use just the first two overloads,
we would break any code that does not pass in a literal string expression.
For example, code like this would be broken:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">mode</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">pick_file_mode</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">mode</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
<span class="c1"># f should continue to be of type IO[Any] here</span>
</pre></div>
</div>
<p>A little more broadly: we propose adding a policy to typeshed that
mandates that whenever we add literal types to some existing API, we also
always include a fallback overload to maintain backwards-compatibility.</p>
</section>
<section id="interactions-with-generics">
<h3><a class="toc-backref" href="#interactions-with-generics" role="doc-backlink">Interactions with generics</a></h3>
<p>Types like <code class="docutils literal notranslate"><span class="pre">Literal[3]</span></code> are meant to be just plain old subclasses of
<code class="docutils literal notranslate"><span class="pre">int</span></code>. This means you can use types like <code class="docutils literal notranslate"><span class="pre">Literal[3]</span></code> anywhere
you could use normal types, such as with generics.</p>
<p>This means that it is legal to parameterize generic functions or
classes using Literal types:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">A</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s1">&#39;A&#39;</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span>
<span class="n">B</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s1">&#39;B&#39;</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span>
<span class="n">C</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s1">&#39;C&#39;</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span>
<span class="c1"># A simplified definition for Matrix[row, column]</span>
<span class="k">class</span> <span class="nc">Matrix</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">]):</span>
<span class="k">def</span> <span class="fm">__add__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">:</span> <span class="n">Matrix</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="o">-&gt;</span> <span class="n">Matrix</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="o">...</span>
<span class="k">def</span> <span class="fm">__matmul__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">:</span> <span class="n">Matrix</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">-&gt;</span> <span class="n">Matrix</span><span class="p">[</span><span class="n">A</span><span class="p">,</span> <span class="n">C</span><span class="p">]:</span> <span class="o">...</span>
<span class="k">def</span> <span class="nf">transpose</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Matrix</span><span class="p">[</span><span class="n">B</span><span class="p">,</span> <span class="n">A</span><span class="p">]:</span> <span class="o">...</span>
<span class="n">foo</span><span class="p">:</span> <span class="n">Matrix</span><span class="p">[</span><span class="n">Literal</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span> <span class="n">Literal</span><span class="p">[</span><span class="mi">3</span><span class="p">]]</span> <span class="o">=</span> <span class="n">Matrix</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="n">bar</span><span class="p">:</span> <span class="n">Matrix</span><span class="p">[</span><span class="n">Literal</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span> <span class="n">Literal</span><span class="p">[</span><span class="mi">7</span><span class="p">]]</span> <span class="o">=</span> <span class="n">Matrix</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="n">baz</span> <span class="o">=</span> <span class="n">foo</span> <span class="o">@</span> <span class="n">bar</span>
<span class="n">reveal_type</span><span class="p">(</span><span class="n">baz</span><span class="p">)</span> <span class="c1"># Revealed type is &#39;Matrix[Literal[2], Literal[7]]&#39;</span>
</pre></div>
</div>
<p>Similarly, it is legal to construct TypeVars with value restrictions
or bounds involving Literal types:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></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="n">Literal</span><span class="p">[</span><span class="s2">&quot;a&quot;</span><span class="p">],</span> <span class="n">Literal</span><span class="p">[</span><span class="s2">&quot;b&quot;</span><span class="p">],</span> <span class="n">Literal</span><span class="p">[</span><span class="s2">&quot;c&quot;</span><span class="p">])</span>
<span class="n">S</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s1">&#39;S&#39;</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="n">Literal</span><span class="p">[</span><span class="s2">&quot;foo&quot;</span><span class="p">])</span>
</pre></div>
</div>
<p>…although it is unclear when it would ever be useful to construct a
TypeVar with a Literal upper bound. For example, the <code class="docutils literal notranslate"><span class="pre">S</span></code> TypeVar in
the above example is essentially pointless: we can get equivalent behavior
by using <code class="docutils literal notranslate"><span class="pre">S</span> <span class="pre">=</span> <span class="pre">Literal[&quot;foo&quot;]</span></code> instead.</p>
<p><strong>Note:</strong> Literal types and generics deliberately interact in only very
basic and limited ways. In particular, libraries that want to type check
code containing a heavy amount of numeric or numpy-style manipulation will
almost certainly likely find Literal types as proposed in this PEP to be
insufficient for their needs.</p>
<p>We considered several different proposals for fixing this, but ultimately
decided to defer the problem of integer generics to a later date. See
<a class="reference internal" href="#rejected-or-out-of-scope-ideas">Rejected or out-of-scope ideas</a> for more details.</p>
</section>
<section id="interactions-with-enums-and-exhaustiveness-checks">
<h3><a class="toc-backref" href="#interactions-with-enums-and-exhaustiveness-checks" role="doc-backlink">Interactions with enums and exhaustiveness checks</a></h3>
<p>Type checkers should be capable of performing exhaustiveness checks when
working Literal types that have a closed number of variants, such as
enums. For example, the type checker should be capable of inferring that
the final <code class="docutils literal notranslate"><span class="pre">else</span></code> statement must be of type <code class="docutils literal notranslate"><span class="pre">str</span></code>, since all three
values of the <code class="docutils literal notranslate"><span class="pre">Status</span></code> enum have already been exhausted:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Status</span><span class="p">(</span><span class="n">Enum</span><span class="p">):</span>
<span class="n">SUCCESS</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">INVALID_DATA</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">FATAL_ERROR</span> <span class="o">=</span> <span class="mi">2</span>
<span class="k">def</span> <span class="nf">parse_status</span><span class="p">(</span><span class="n">s</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Status</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">if</span> <span class="n">s</span> <span class="ow">is</span> <span class="n">Status</span><span class="o">.</span><span class="n">SUCCESS</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Success!&quot;</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">s</span> <span class="ow">is</span> <span class="n">Status</span><span class="o">.</span><span class="n">INVALID_DATA</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;The given data is invalid because...&quot;</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">s</span> <span class="ow">is</span> <span class="n">Status</span><span class="o">.</span><span class="n">FATAL_ERROR</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Unexpected fatal error...&quot;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># &#39;s&#39; must be of type &#39;str&#39; since all other options are exhausted</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Got custom status: &quot;</span> <span class="o">+</span> <span class="n">s</span><span class="p">)</span>
</pre></div>
</div>
<p>The interaction described above is not new: its already
<a class="pep reference internal" href="../pep-0484/#support-for-singleton-types-in-unions" title="PEP 484 Type Hints § Support for singleton types in unions">codified within PEP 484</a>.
However, many type
checkers (such as mypy) do not yet implement this due to the expected
complexity of the implementation work.</p>
<p>Some of this complexity will be alleviated once Literal types are introduced:
rather than entirely special-casing enums, we can instead treat them as being
approximately equivalent to the union of their values and take advantage of any
existing logic regarding unions, exhaustibility, type narrowing, reachability,
and so forth the type checker might have already implemented.</p>
<p>So here, the <code class="docutils literal notranslate"><span class="pre">Status</span></code> enum could be treated as being approximately equivalent
to <code class="docutils literal notranslate"><span class="pre">Literal[Status.SUCCESS,</span> <span class="pre">Status.INVALID_DATA,</span> <span class="pre">Status.FATAL_ERROR]</span></code>
and the type of <code class="docutils literal notranslate"><span class="pre">s</span></code> narrowed accordingly.</p>
</section>
<section id="interactions-with-narrowing">
<h3><a class="toc-backref" href="#interactions-with-narrowing" role="doc-backlink">Interactions with narrowing</a></h3>
<p>Type checkers may optionally perform additional analysis for both enum and
non-enum Literal types beyond what is described in the section above.</p>
<p>For example, it may be useful to perform narrowing based on things like
containment or equality checks:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">parse_status</span><span class="p">(</span><span class="n">status</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">if</span> <span class="n">status</span> <span class="ow">in</span> <span class="p">(</span><span class="s2">&quot;MALFORMED&quot;</span><span class="p">,</span> <span class="s2">&quot;ABORTED&quot;</span><span class="p">):</span>
<span class="c1"># Type checker could narrow &#39;status&#39; to type</span>
<span class="c1"># Literal[&quot;MALFORMED&quot;, &quot;ABORTED&quot;] here.</span>
<span class="k">return</span> <span class="n">expects_bad_status</span><span class="p">(</span><span class="n">status</span><span class="p">)</span>
<span class="c1"># Similarly, type checker could narrow &#39;status&#39; to Literal[&quot;PENDING&quot;]</span>
<span class="k">if</span> <span class="n">status</span> <span class="o">==</span> <span class="s2">&quot;PENDING&quot;</span><span class="p">:</span>
<span class="n">expects_pending_status</span><span class="p">(</span><span class="n">status</span><span class="p">)</span>
</pre></div>
</div>
<p>It may also be useful to perform narrowing taking into account expressions
involving Literal bools. For example, we can combine <code class="docutils literal notranslate"><span class="pre">Literal[True]</span></code>,
<code class="docutils literal notranslate"><span class="pre">Literal[False]</span></code>, and overloads to construct “custom type guards”:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@overload</span>
<span class="k">def</span> <span class="nf">is_int_like</span><span class="p">(</span><span class="n">x</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">List</span><span class="p">[</span><span class="nb">int</span><span class="p">]])</span> <span class="o">-&gt;</span> <span class="n">Literal</span><span class="p">[</span><span class="kc">True</span><span class="p">]:</span> <span class="o">...</span>
<span class="nd">@overload</span>
<span class="k">def</span> <span class="nf">is_int_like</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="nb">object</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span> <span class="o">...</span>
<span class="k">def</span> <span class="nf">is_int_like</span><span class="p">(</span><span class="n">x</span><span class="p">):</span> <span class="o">...</span>
<span class="n">vector</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">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span>
<span class="k">if</span> <span class="n">is_int_like</span><span class="p">(</span><span class="n">vector</span><span class="p">):</span>
<span class="n">vector</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">vector</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;bad&quot;</span><span class="p">)</span> <span class="c1"># This branch is inferred to be unreachable</span>
<span class="n">scalar</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">str</span><span class="p">]</span>
<span class="k">if</span> <span class="n">is_int_like</span><span class="p">(</span><span class="n">scalar</span><span class="p">):</span>
<span class="n">scalar</span> <span class="o">+=</span> <span class="mi">3</span> <span class="c1"># Type checks: type of &#39;scalar&#39; is narrowed to &#39;int&#39;</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">scalar</span> <span class="o">+=</span> <span class="s2">&quot;foo&quot;</span> <span class="c1"># Type checks: type of &#39;scalar&#39; is narrowed to &#39;str&#39;</span>
</pre></div>
</div>
</section>
<section id="interactions-with-final">
<h3><a class="toc-backref" href="#interactions-with-final" role="doc-backlink">Interactions with Final</a></h3>
<p><a class="pep reference internal" href="../pep-0591/" title="PEP 591 Adding a final qualifier to typing">PEP 591</a> proposes adding a “Final” qualifier to the typing
ecosystem. This qualifier can be used to declare that some variable or
attribute cannot be reassigned:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">foo</span><span class="p">:</span> <span class="n">Final</span> <span class="o">=</span> <span class="mi">3</span>
<span class="n">foo</span> <span class="o">=</span> <span class="mi">4</span> <span class="c1"># Error: &#39;foo&#39; is declared to be Final</span>
</pre></div>
</div>
<p>Note that in the example above, we know that <code class="docutils literal notranslate"><span class="pre">foo</span></code> will always be equal to
exactly <code class="docutils literal notranslate"><span class="pre">3</span></code>. A type checker can use this information to deduce that <code class="docutils literal notranslate"><span class="pre">foo</span></code>
is valid to use in any context that expects a <code class="docutils literal notranslate"><span class="pre">Literal[3]</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">expects_three</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="mi">3</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span> <span class="o">...</span>
<span class="n">expects_three</span><span class="p">(</span><span class="n">foo</span><span class="p">)</span> <span class="c1"># Type checks, since &#39;foo&#39; is Final and equal to 3</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">Final</span></code> qualifier serves as a shorthand for declaring that a variable
is <em>effectively Literal</em>.</p>
<p>If both this PEP and <a class="pep reference internal" href="../pep-0591/" title="PEP 591 Adding a final qualifier to typing">PEP 591</a> are accepted, type checkers are expected to
support this shortcut. Specifically, given a variable or attribute assignment
of the form <code class="docutils literal notranslate"><span class="pre">var:</span> <span class="pre">Final</span> <span class="pre">=</span> <span class="pre">value</span></code> where <code class="docutils literal notranslate"><span class="pre">value</span></code> is a valid parameter for
<code class="docutils literal notranslate"><span class="pre">Literal[...]</span></code>, type checkers should understand that <code class="docutils literal notranslate"><span class="pre">var</span></code> may be used in
any context that expects a <code class="docutils literal notranslate"><span class="pre">Literal[value]</span></code>.</p>
<p>Type checkers are not obligated to understand any other uses of Final. For
example, whether or not the following program type checks is left unspecified:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Note: The assignment does not exactly match the form &#39;var: Final = value&#39;.</span>
<span class="n">bar1</span><span class="p">:</span> <span class="n">Final</span><span class="p">[</span><span class="nb">int</span><span class="p">]</span> <span class="o">=</span> <span class="mi">3</span>
<span class="n">expects_three</span><span class="p">(</span><span class="n">bar1</span><span class="p">)</span> <span class="c1"># May or may not be accepted by type checkers</span>
<span class="c1"># Note: &quot;Literal[1 + 2]&quot; is not a legal type.</span>
<span class="n">bar2</span><span class="p">:</span> <span class="n">Final</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">+</span> <span class="mi">2</span>
<span class="n">expects_three</span><span class="p">(</span><span class="n">bar2</span><span class="p">)</span> <span class="c1"># May or may not be accepted by type checkers</span>
</pre></div>
</div>
</section>
</section>
<section id="rejected-or-out-of-scope-ideas">
<h2><a class="toc-backref" href="#rejected-or-out-of-scope-ideas" role="doc-backlink">Rejected or out-of-scope ideas</a></h2>
<p>This section outlines some potential features that are explicitly out-of-scope.</p>
<section id="true-dependent-types-integer-generics">
<h3><a class="toc-backref" href="#true-dependent-types-integer-generics" role="doc-backlink">True dependent types/integer generics</a></h3>
<p>This proposal is essentially describing adding a very simplified
dependent type system to the <a class="pep reference internal" href="../pep-0484/" title="PEP 484 Type Hints">PEP 484</a> ecosystem. One obvious extension
would be to implement a full-fledged dependent type system that lets users
predicate types based on their values in arbitrary ways. That would
let us write signatures like the below:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># A vector has length &#39;n&#39;, containing elements of type &#39;T&#39;</span>
<span class="k">class</span> <span class="nc">Vector</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">N</span><span class="p">,</span> <span class="n">T</span><span class="p">]):</span> <span class="o">...</span>
<span class="c1"># The type checker will statically verify our function genuinely does</span>
<span class="c1"># construct a vector that is equal in length to &quot;len(vec1) + len(vec2)&quot;</span>
<span class="c1"># and will throw an error if it does not.</span>
<span class="k">def</span> <span class="nf">concat</span><span class="p">(</span><span class="n">vec1</span><span class="p">:</span> <span class="n">Vector</span><span class="p">[</span><span class="n">A</span><span class="p">,</span> <span class="n">T</span><span class="p">],</span> <span class="n">vec2</span><span class="p">:</span> <span class="n">Vector</span><span class="p">[</span><span class="n">B</span><span class="p">,</span> <span class="n">T</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">Vector</span><span class="p">[</span><span class="n">A</span> <span class="o">+</span> <span class="n">B</span><span class="p">,</span> <span class="n">T</span><span class="p">]:</span>
<span class="c1"># ...snip...</span>
</pre></div>
</div>
<p>At the very least, it would be useful to add some form of integer generics.</p>
<p>Although such a type system would certainly be useful, its out of scope
for this PEP: it would require a far more substantial amount of implementation
work, discussion, and research to complete compared to the current proposal.</p>
<p>Its entirely possible well circle back and revisit this topic in the future:
we very likely will need some form of dependent typing along with other
extensions like variadic generics to support popular libraries like numpy.</p>
<p>This PEP should be seen as a stepping stone towards this goal,
rather than an attempt at providing a comprehensive solution.</p>
</section>
<section id="adding-more-concise-syntax">
<h3><a class="toc-backref" href="#adding-more-concise-syntax" role="doc-backlink">Adding more concise syntax</a></h3>
<p>One objection to this PEP is that having to explicitly write <code class="docutils literal notranslate"><span class="pre">Literal[...]</span></code>
feels verbose. For example, instead of writing:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">foobar</span><span class="p">(</span><span class="n">arg1</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">arg2</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="kc">True</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">pass</span>
</pre></div>
</div>
<p>…it would be nice to instead write:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">foobar</span><span class="p">(</span><span class="n">arg1</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="n">arg2</span><span class="p">:</span> <span class="kc">True</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">pass</span>
</pre></div>
</div>
<p>Unfortunately, these abbreviations simply will not work with the
existing implementation of <code class="docutils literal notranslate"><span class="pre">typing</span></code> at runtime. For example, the
following snippet crashes when run using Python 3.7:</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">Tuple</span>
<span class="c1"># Supposed to accept tuple containing the literals 1 and 2</span>
<span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="n">Tuple</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">pass</span>
</pre></div>
</div>
<p>Running this yields the following exception:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="ne">TypeError</span><span class="p">:</span> <span class="n">Tuple</span><span class="p">[</span><span class="n">t0</span><span class="p">,</span> <span class="n">t1</span><span class="p">,</span> <span class="o">...</span><span class="p">]:</span> <span class="n">each</span> <span class="n">t</span> <span class="n">must</span> <span class="n">be</span> <span class="n">a</span> <span class="nb">type</span><span class="o">.</span> <span class="n">Got</span> <span class="mf">1.</span>
</pre></div>
</div>
<p>We dont want users to have to memorize exactly when its ok to elide
<code class="docutils literal notranslate"><span class="pre">Literal</span></code>, so we require <code class="docutils literal notranslate"><span class="pre">Literal</span></code> to always be present.</p>
<p>A little more broadly, we feel overhauling the syntax of types in
Python is not within the scope of this PEP: it would be best to have
that discussion in a separate PEP, instead of attaching it to this one.
So, this PEP deliberately does not try and innovate Pythons type syntax.</p>
</section>
</section>
<section id="backporting-the-literal-type">
<h2><a class="toc-backref" href="#backporting-the-literal-type" role="doc-backlink">Backporting the <code class="docutils literal notranslate"><span class="pre">Literal</span></code> type</a></h2>
<p>Once this PEP is accepted, the <code class="docutils literal notranslate"><span class="pre">Literal</span></code> type will need to be backported for
Python versions that come bundled with older versions of the <code class="docutils literal notranslate"><span class="pre">typing</span></code> module.
We plan to do this by adding <code class="docutils literal notranslate"><span class="pre">Literal</span></code> to the <code class="docutils literal notranslate"><span class="pre">typing_extensions</span></code> 3rd party
module, which contains a variety of other backported types.</p>
</section>
<section id="implementation">
<h2><a class="toc-backref" href="#implementation" role="doc-backlink">Implementation</a></h2>
<p>The mypy type checker currently has implemented a large subset of the behavior
described in this spec, with the exception of enum Literals and some of the
more complex narrowing interactions described above.</p>
</section>
<section id="related-work">
<h2><a class="toc-backref" href="#related-work" role="doc-backlink">Related work</a></h2>
<p>This proposal was written based on the discussion that took place in the
following threads:</p>
<ul class="simple">
<li><a class="reference external" href="https://github.com/python/typing/issues/478">Check that literals belong to/are excluded from a set of values</a></li>
<li><a class="reference external" href="https://github.com/python/mypy/issues/3062">Simple dependent types</a></li>
<li><a class="reference external" href="https://github.com/python/typing/issues/513">Typing for multi-dimensional arrays</a></li>
</ul>
<p>The overall design of this proposal also ended up converging into
something similar to how
<a class="reference external" href="https://www.typescriptlang.org/docs/handbook/advanced-types.html#string-literal_types">literal types are handled in TypeScript</a>.</p>
</section>
<section id="acknowledgements">
<h2><a class="toc-backref" href="#acknowledgements" role="doc-backlink">Acknowledgements</a></h2>
<p>Thanks to Mark Mendoza, Ran Benita, Rebecca Chen, and the other members of
typing-sig for their comments on this PEP.</p>
<p>Additional thanks to the various participants in the mypy and typing issue
trackers, who helped provide a lot of the motivation and reasoning behind
this PEP.</p>
</section>
<section id="copyright">
<h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2>
<p>This document has been placed in the public domain.</p>
</section>
</section>
<hr class="docutils" />
<p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0586.rst">https://github.com/python/peps/blob/main/peps/pep-0586.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0586.rst">2024-02-14 20:29:34 GMT</a></p>
</article>
<nav id="pep-sidebar">
<h2>Contents</h2>
<ul>
<li><a class="reference internal" href="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#motivation-and-rationale">Motivation and Rationale</a></li>
<li><a class="reference internal" href="#core-semantics">Core Semantics</a><ul>
<li><a class="reference internal" href="#core-behavior">Core behavior</a></li>
<li><a class="reference internal" href="#equivalence-of-two-literals">Equivalence of two Literals</a></li>
<li><a class="reference internal" href="#shortening-unions-of-literals">Shortening unions of literals</a></li>
</ul>
</li>
<li><a class="reference internal" href="#legal-and-illegal-parameterizations">Legal and illegal parameterizations</a><ul>
<li><a class="reference internal" href="#legal-parameters-for-literal-at-type-check-time">Legal parameters for <code class="docutils literal notranslate"><span class="pre">Literal</span></code> at type check time</a></li>
<li><a class="reference internal" href="#illegal-parameters-for-literal-at-type-check-time">Illegal parameters for <code class="docutils literal notranslate"><span class="pre">Literal</span></code> at type check time</a></li>
<li><a class="reference internal" href="#parameters-at-runtime">Parameters at runtime</a></li>
<li><a class="reference internal" href="#literals-enums-and-forward-references">Literals, enums, and forward references</a></li>
</ul>
</li>
<li><a class="reference internal" href="#type-inference">Type inference</a><ul>
<li><a class="reference internal" href="#backwards-compatibility">Backwards compatibility</a></li>
<li><a class="reference internal" href="#using-non-literals-in-literal-contexts">Using non-Literals in Literal contexts</a></li>
</ul>
</li>
<li><a class="reference internal" href="#interactions-with-other-types-and-features">Interactions with other types and features</a><ul>
<li><a class="reference internal" href="#intelligent-indexing-of-structured-data">Intelligent indexing of structured data</a></li>
<li><a class="reference internal" href="#interactions-with-overloads">Interactions with overloads</a></li>
<li><a class="reference internal" href="#interactions-with-generics">Interactions with generics</a></li>
<li><a class="reference internal" href="#interactions-with-enums-and-exhaustiveness-checks">Interactions with enums and exhaustiveness checks</a></li>
<li><a class="reference internal" href="#interactions-with-narrowing">Interactions with narrowing</a></li>
<li><a class="reference internal" href="#interactions-with-final">Interactions with Final</a></li>
</ul>
</li>
<li><a class="reference internal" href="#rejected-or-out-of-scope-ideas">Rejected or out-of-scope ideas</a><ul>
<li><a class="reference internal" href="#true-dependent-types-integer-generics">True dependent types/integer generics</a></li>
<li><a class="reference internal" href="#adding-more-concise-syntax">Adding more concise syntax</a></li>
</ul>
</li>
<li><a class="reference internal" href="#backporting-the-literal-type">Backporting the <code class="docutils literal notranslate"><span class="pre">Literal</span></code> type</a></li>
<li><a class="reference internal" href="#implementation">Implementation</a></li>
<li><a class="reference internal" href="#related-work">Related work</a></li>
<li><a class="reference internal" href="#acknowledgements">Acknowledgements</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-0586.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>