CINXE.COM
PEP 526 – Syntax for Variable Annotations | peps.python.org
<!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 526 – Syntax for Variable Annotations | peps.python.org</title> <link rel="shortcut icon" href="../_static/py.png"> <link rel="canonical" href="https://peps.python.org/pep-0526/"> <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 526 – Syntax for Variable Annotations | peps.python.org'> <meta property="og:description" content="PEP 484 introduced type hints, a.k.a. type annotations. While its main focus was function annotations, it also introduced the notion of type comments to annotate variables:"> <meta property="og:type" content="website"> <meta property="og:url" content="https://peps.python.org/pep-0526/"> <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="PEP 484 introduced type hints, a.k.a. type annotations. While its main focus was function annotations, it also introduced the notion of type comments to annotate variables:"> <meta name="theme-color" content="#3776ab"> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all"> <title>Following system colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="9"></circle> <path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path> </svg> </symbol> <symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all"> <title>Selected dark colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path stroke="none" d="M0 0h24v24H0z" fill="none"></path> <path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path> </svg> </symbol> <symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all"> <title>Selected light colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="5"></circle> <line x1="12" y1="1" x2="12" y2="3"></line> <line x1="12" y1="21" x2="12" y2="23"></line> <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line> <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line> <line x1="1" y1="12" x2="3" y2="12"></line> <line x1="21" y1="12" x2="23" y2="12"></line> <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line> <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line> </svg> </symbol> </svg> <script> document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto" </script> <section id="pep-page-section"> <header> <h1>Python Enhancement Proposals</h1> <ul class="breadcrumbs"> <li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> » </li> <li><a href="../pep-0000/">PEP Index</a> » </li> <li>PEP 526</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 526 – Syntax for Variable Annotations</h1> <dl class="rfc2822 field-list simple"> <dt class="field-odd">Author<span class="colon">:</span></dt> <dd class="field-odd">Ryan Gonzalez <rymg19 at gmail.com>, Philip House <phouse512 at gmail.com>, Ivan Levkivskyi <levkivskyi at gmail.com>, Lisa Roach <lisaroach14 at gmail.com>, Guido van Rossum <guido at python.org></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">09-Aug-2016</dd> <dt class="field-even">Python-Version<span class="colon">:</span></dt> <dd class="field-even">3.6</dd> <dt class="field-odd">Post-History<span class="colon">:</span></dt> <dd class="field-odd">30-Aug-2016, 02-Sep-2016</dd> <dt class="field-even">Resolution<span class="colon">:</span></dt> <dd class="field-even"><a class="reference external" href="https://mail.python.org/pipermail/python-dev/2016-September/146282.html">Python-Dev 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="#status">Status</a></li> <li><a class="reference internal" href="#notice-for-reviewers">Notice for Reviewers</a></li> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#rationale">Rationale</a><ul> <li><a class="reference internal" href="#non-goals">Non-goals</a></li> </ul> </li> <li><a class="reference internal" href="#specification">Specification</a><ul> <li><a class="reference internal" href="#global-and-local-variable-annotations">Global and local variable annotations</a></li> <li><a class="reference internal" href="#class-and-instance-variable-annotations">Class and instance variable annotations</a></li> <li><a class="reference internal" href="#annotating-expressions">Annotating expressions</a></li> <li><a class="reference internal" href="#where-annotations-aren-t-allowed">Where annotations aren’t allowed</a></li> <li><a class="reference internal" href="#variable-annotations-in-stub-files">Variable annotations in stub files</a></li> <li><a class="reference internal" href="#preferred-coding-style-for-variable-annotations">Preferred coding style for variable annotations</a></li> </ul> </li> <li><a class="reference internal" href="#changes-to-standard-library-and-documentation">Changes to Standard Library and Documentation</a></li> <li><a class="reference internal" href="#runtime-effects-of-type-annotations">Runtime Effects of Type Annotations</a><ul> <li><a class="reference internal" href="#other-uses-of-annotations">Other uses of annotations</a></li> </ul> </li> <li><a class="reference internal" href="#rejected-postponed-proposals">Rejected/Postponed Proposals</a></li> <li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a></li> <li><a class="reference internal" href="#implementation">Implementation</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 important"> <p class="admonition-title">Important</p> <p>This PEP is a historical document: see <a class="reference external" href="https://docs.python.org/3/reference/simple_stmts.html#annassign" title="(in Python v3.13)"><span>Annotated assignment statements</span></a>, <a class="reference external" href="https://typing.readthedocs.io/en/latest/spec/class-compat.html#classvar" title="(in typing)"><span>ClassVar</span></a> and <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.ClassVar" title="(in Python v3.13)"><code class="xref py py-data docutils literal notranslate"><span class="pre">typing.ClassVar</span></code></a> for up-to-date specs and documentation. Canonical typing specs are maintained at the <a class="reference external" href="https://typing.readthedocs.io/en/latest/spec/">typing specs site</a>; runtime typing behaviour is described in the CPython documentation.</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 to the typing spec.</p> </div> <section id="status"> <h2><a class="toc-backref" href="#status" role="doc-backlink">Status</a></h2> <p>This PEP has been provisionally accepted by the BDFL. See the acceptance message for more color: <a class="reference external" href="https://mail.python.org/pipermail/python-dev/2016-September/146282.html">https://mail.python.org/pipermail/python-dev/2016-September/146282.html</a></p> </section> <section id="notice-for-reviewers"> <h2><a class="toc-backref" href="#notice-for-reviewers" role="doc-backlink">Notice for Reviewers</a></h2> <p>This PEP was drafted in a separate repo: <a class="reference external" href="https://github.com/phouse512/peps/tree/pep-0526">https://github.com/phouse512/peps/tree/pep-0526</a>.</p> <p>There was preliminary discussion on python-ideas and at <a class="reference external" href="https://github.com/python/typing/issues/258">https://github.com/python/typing/issues/258</a>.</p> <p>Before you bring up an objection in a public forum please at least read the summary of <a class="reference internal" href="#pep-526-rejected">rejected ideas</a> listed at the end of this PEP.</p> </section> <section id="abstract"> <h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2> <p><a class="pep reference internal" href="../pep-0484/" title="PEP 484 – Type Hints">PEP 484</a> introduced type hints, a.k.a. type annotations. While its main focus was function annotations, it also introduced the notion of type comments to annotate variables:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># 'primes' is a list of integers</span> <span class="n">primes</span> <span class="o">=</span> <span class="p">[]</span> <span class="c1"># type: List[int]</span> <span class="c1"># 'captain' is a string (Note: initial value is a problem)</span> <span class="n">captain</span> <span class="o">=</span> <span class="o">...</span> <span class="c1"># type: str</span> <span class="k">class</span><span class="w"> </span><span class="nc">Starship</span><span class="p">:</span> <span class="c1"># 'stats' is a class variable</span> <span class="n">stats</span> <span class="o">=</span> <span class="p">{}</span> <span class="c1"># type: Dict[str, int]</span> </pre></div> </div> <p>This PEP aims at adding syntax to Python for annotating the types of variables (including class variables and instance variables), instead of expressing them through comments:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">primes</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="n">captain</span><span class="p">:</span> <span class="nb">str</span> <span class="c1"># Note: no initial value!</span> <span class="k">class</span><span class="w"> </span><span class="nc">Starship</span><span class="p">:</span> <span class="n">stats</span><span class="p">:</span> <span class="n">ClassVar</span><span class="p">[</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">int</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span> </pre></div> </div> <p><a class="pep reference internal" href="../pep-0484/" title="PEP 484 – Type Hints">PEP 484</a> explicitly states that type comments are intended to help with type inference in complex cases, and this PEP does not change this intention. However, since in practice type comments have also been adopted for class variables and instance variables, this PEP also discusses the use of type annotations for those variables.</p> </section> <section id="rationale"> <h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2> <p>Although type comments work well enough, the fact that they’re expressed through comments has some downsides:</p> <ul> <li>Text editors often highlight comments differently from type annotations.</li> <li>There’s no way to annotate the type of an undefined variable; one needs to initialize it to <code class="docutils literal notranslate"><span class="pre">None</span></code> (e.g. <code class="docutils literal notranslate"><span class="pre">a</span> <span class="pre">=</span> <span class="pre">None</span> <span class="pre">#</span> <span class="pre">type:</span> <span class="pre">int</span></code>).</li> <li>Variables annotated in a conditional branch are difficult to read:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="n">some_value</span><span class="p">:</span> <span class="n">my_var</span> <span class="o">=</span> <span class="n">function</span><span class="p">()</span> <span class="c1"># type: Logger</span> <span class="k">else</span><span class="p">:</span> <span class="n">my_var</span> <span class="o">=</span> <span class="n">another_function</span><span class="p">()</span> <span class="c1"># Why isn't there a type here?</span> </pre></div> </div> </li> <li>Since type comments aren’t actually part of the language, if a Python script wants to parse them, it requires a custom parser instead of just using <code class="docutils literal notranslate"><span class="pre">ast</span></code>.</li> <li>Type comments are used a lot in typeshed. Migrating typeshed to use the variable annotation syntax instead of type comments would improve readability of stubs.</li> <li>In situations where normal comments and type comments are used together, it is difficult to distinguish them:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">path</span> <span class="o">=</span> <span class="kc">None</span> <span class="c1"># type: Optional[str] # Path to module source</span> </pre></div> </div> </li> <li>It’s impossible to retrieve the annotations at runtime outside of attempting to find the module’s source code and parse it at runtime, which is inelegant, to say the least.</li> </ul> <p>The majority of these issues can be alleviated by making the syntax a core part of the language. Moreover, having a dedicated annotation syntax for class and instance variables (in addition to method annotations) will pave the way to static duck-typing as a complement to nominal typing defined by <a class="pep reference internal" href="../pep-0484/" title="PEP 484 – Type Hints">PEP 484</a>.</p> <section id="non-goals"> <h3><a class="toc-backref" href="#non-goals" role="doc-backlink">Non-goals</a></h3> <p>While the proposal is accompanied by an extension of the <code class="docutils literal notranslate"><span class="pre">typing.get_type_hints</span></code> standard library function for runtime retrieval of annotations, variable annotations are not designed for runtime type checking. Third party packages will have to be developed to implement such functionality.</p> <p>It should also be emphasized that <strong>Python will remain a dynamically typed language, and the authors have no desire to ever make type hints mandatory, even by convention.</strong> Type annotations should not be confused with variable declarations in statically typed languages. The goal of annotation syntax is to provide an easy way to specify structured type metadata for third party tools.</p> <p>This PEP does not require type checkers to change their type checking rules. It merely provides a more readable syntax to replace type comments.</p> </section> </section> <section id="specification"> <h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2> <p>Type annotation can be added to an assignment statement or to a single expression indicating the desired type of the annotation target to a third party type checker:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">my_var</span><span class="p">:</span> <span class="nb">int</span> <span class="n">my_var</span> <span class="o">=</span> <span class="mi">5</span> <span class="c1"># Passes type check.</span> <span class="n">other_var</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="s1">'a'</span> <span class="c1"># Flagged as error by type checker,</span> <span class="c1"># but OK at runtime.</span> </pre></div> </div> <p>This syntax does not introduce any new semantics beyond <a class="pep reference internal" href="../pep-0484/" title="PEP 484 – Type Hints">PEP 484</a>, so that the following three statements are equivalent:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">var</span> <span class="o">=</span> <span class="n">value</span> <span class="c1"># type: annotation</span> <span class="n">var</span><span class="p">:</span> <span class="n">annotation</span><span class="p">;</span> <span class="n">var</span> <span class="o">=</span> <span class="n">value</span> <span class="n">var</span><span class="p">:</span> <span class="n">annotation</span> <span class="o">=</span> <span class="n">value</span> </pre></div> </div> <p>Below we specify the syntax of type annotations in different contexts and their runtime effects.</p> <p>We also suggest how type checkers might interpret annotations, but compliance to these suggestions is not mandatory. (This is in line with the attitude towards compliance in <a class="pep reference internal" href="../pep-0484/" title="PEP 484 – Type Hints">PEP 484</a>.)</p> <section id="global-and-local-variable-annotations"> <h3><a class="toc-backref" href="#global-and-local-variable-annotations" role="doc-backlink">Global and local variable annotations</a></h3> <p>The types of locals and globals can be annotated as follows:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">some_number</span><span class="p">:</span> <span class="nb">int</span> <span class="c1"># variable without initial value</span> <span class="n">some_list</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="c1"># variable with initial value</span> </pre></div> </div> <p>Being able to omit the initial value allows for easier typing of variables assigned in conditional branches:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">sane_world</span><span class="p">:</span> <span class="nb">bool</span> <span class="k">if</span> <span class="mi">2</span><span class="o">+</span><span class="mi">2</span> <span class="o">==</span> <span class="mi">4</span><span class="p">:</span> <span class="n">sane_world</span> <span class="o">=</span> <span class="kc">True</span> <span class="k">else</span><span class="p">:</span> <span class="n">sane_world</span> <span class="o">=</span> <span class="kc">False</span> </pre></div> </div> <p>Note that, although the syntax does allow tuple packing, it does <em>not</em> allow one to annotate the types of variables when tuple unpacking is used:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Tuple packing with variable annotation syntax</span> <span class="n">t</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="o">...</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="c1"># or</span> <span class="n">t</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="o">...</span><span class="p">]</span> <span class="o">=</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="c1"># This only works in Python 3.8+</span> <span class="c1"># Tuple unpacking with variable annotation syntax</span> <span class="n">header</span><span class="p">:</span> <span class="nb">str</span> <span class="n">kind</span><span class="p">:</span> <span class="nb">int</span> <span class="n">body</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]]</span> <span class="n">header</span><span class="p">,</span> <span class="n">kind</span><span class="p">,</span> <span class="n">body</span> <span class="o">=</span> <span class="n">message</span> </pre></div> </div> <p>Omitting the initial value leaves the variable uninitialized:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">a</span><span class="p">:</span> <span class="nb">int</span> <span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="c1"># raises NameError</span> </pre></div> </div> <p>However, annotating a local variable will cause the interpreter to always make it a local:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">f</span><span class="p">():</span> <span class="n">a</span><span class="p">:</span> <span class="nb">int</span> <span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="c1"># raises UnboundLocalError</span> <span class="c1"># Commenting out the a: int makes it a NameError.</span> </pre></div> </div> <p>as if the code were:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">f</span><span class="p">():</span> <span class="k">if</span> <span class="kc">False</span><span class="p">:</span> <span class="n">a</span> <span class="o">=</span> <span class="mi">0</span> <span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="c1"># raises UnboundLocalError</span> </pre></div> </div> <p>Duplicate type annotations will be ignored. However, static type checkers may issue a warning for annotations of the same variable by a different type:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">a</span><span class="p">:</span> <span class="nb">int</span> <span class="n">a</span><span class="p">:</span> <span class="nb">str</span> <span class="c1"># Static type checker may or may not warn about this.</span> </pre></div> </div> </section> <section id="class-and-instance-variable-annotations"> <span id="classvar"></span><h3><a class="toc-backref" href="#class-and-instance-variable-annotations" role="doc-backlink">Class and instance variable annotations</a></h3> <p>Type annotations can also be used to annotate class and instance variables in class bodies and methods. In particular, the value-less notation <code class="docutils literal notranslate"><span class="pre">a:</span> <span class="pre">int</span></code> allows one to annotate instance variables that should be initialized in <code class="docutils literal notranslate"><span class="pre">__init__</span></code> or <code class="docutils literal notranslate"><span class="pre">__new__</span></code>. The proposed syntax is as follows:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">BasicStarship</span><span class="p">:</span> <span class="n">captain</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s1">'Picard'</span> <span class="c1"># instance variable with default</span> <span class="n">damage</span><span class="p">:</span> <span class="nb">int</span> <span class="c1"># instance variable without default</span> <span class="n">stats</span><span class="p">:</span> <span class="n">ClassVar</span><span class="p">[</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">int</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span> <span class="c1"># class variable</span> </pre></div> </div> <p>Here <code class="docutils literal notranslate"><span class="pre">ClassVar</span></code> is a special class defined by the typing module that indicates to the static type checker that this variable should not be set on instances.</p> <p>Note that a <code class="docutils literal notranslate"><span class="pre">ClassVar</span></code> parameter cannot include any type variables, regardless of the level of nesting: <code class="docutils literal notranslate"><span class="pre">ClassVar[T]</span></code> and <code class="docutils literal notranslate"><span class="pre">ClassVar[List[Set[T]]]</span></code> are both invalid if <code class="docutils literal notranslate"><span class="pre">T</span></code> is a type variable.</p> <p>This could be illustrated with a more detailed example. In this class:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">Starship</span><span class="p">:</span> <span class="n">captain</span> <span class="o">=</span> <span class="s1">'Picard'</span> <span class="n">stats</span> <span class="o">=</span> <span class="p">{}</span> <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">damage</span><span class="p">,</span> <span class="n">captain</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">damage</span> <span class="o">=</span> <span class="n">damage</span> <span class="k">if</span> <span class="n">captain</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">captain</span> <span class="o">=</span> <span class="n">captain</span> <span class="c1"># Else keep the default</span> <span class="k">def</span><span class="w"> </span><span class="nf">hit</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="n">Starship</span><span class="o">.</span><span class="n">stats</span><span class="p">[</span><span class="s1">'hits'</span><span class="p">]</span> <span class="o">=</span> <span class="n">Starship</span><span class="o">.</span><span class="n">stats</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'hits'</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span> </pre></div> </div> <p><code class="docutils literal notranslate"><span class="pre">stats</span></code> is intended to be a class variable (keeping track of many different per-game statistics), while <code class="docutils literal notranslate"><span class="pre">captain</span></code> is an instance variable with a default value set in the class. This difference might not be seen by a type checker: both get initialized in the class, but <code class="docutils literal notranslate"><span class="pre">captain</span></code> serves only as a convenient default value for the instance variable, while <code class="docutils literal notranslate"><span class="pre">stats</span></code> is truly a class variable – it is intended to be shared by all instances.</p> <p>Since both variables happen to be initialized at the class level, it is useful to distinguish them by marking class variables as annotated with types wrapped in <code class="docutils literal notranslate"><span class="pre">ClassVar[...]</span></code>. In this way a type checker may flag accidental assignments to attributes with the same name on instances.</p> <p>For example, annotating the discussed class:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">Starship</span><span class="p">:</span> <span class="n">captain</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s1">'Picard'</span> <span class="n">damage</span><span class="p">:</span> <span class="nb">int</span> <span class="n">stats</span><span class="p">:</span> <span class="n">ClassVar</span><span class="p">[</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">int</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span> <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">damage</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">captain</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="kc">None</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">damage</span> <span class="o">=</span> <span class="n">damage</span> <span class="k">if</span> <span class="n">captain</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">captain</span> <span class="o">=</span> <span class="n">captain</span> <span class="c1"># Else keep the default</span> <span class="k">def</span><span class="w"> </span><span class="nf">hit</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="n">Starship</span><span class="o">.</span><span class="n">stats</span><span class="p">[</span><span class="s1">'hits'</span><span class="p">]</span> <span class="o">=</span> <span class="n">Starship</span><span class="o">.</span><span class="n">stats</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'hits'</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span> <span class="n">enterprise_d</span> <span class="o">=</span> <span class="n">Starship</span><span class="p">(</span><span class="mi">3000</span><span class="p">)</span> <span class="n">enterprise_d</span><span class="o">.</span><span class="n">stats</span> <span class="o">=</span> <span class="p">{}</span> <span class="c1"># Flagged as error by a type checker</span> <span class="n">Starship</span><span class="o">.</span><span class="n">stats</span> <span class="o">=</span> <span class="p">{}</span> <span class="c1"># This is OK</span> </pre></div> </div> <p>As a matter of convenience (and convention), instance variables can be annotated in <code class="docutils literal notranslate"><span class="pre">__init__</span></code> or other methods, rather than in the class:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Generic</span><span class="p">,</span> <span class="n">TypeVar</span> <span class="n">T</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s1">'T'</span><span class="p">)</span> <span class="k">class</span><span class="w"> </span><span class="nc">Box</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">T</span><span class="p">]):</span> <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">content</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">content</span><span class="p">:</span> <span class="n">T</span> <span class="o">=</span> <span class="n">content</span> </pre></div> </div> </section> <section id="annotating-expressions"> <h3><a class="toc-backref" href="#annotating-expressions" role="doc-backlink">Annotating expressions</a></h3> <p>The target of the annotation can be any valid single assignment target, at least syntactically (it is up to the type checker what to do with this):</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">Cls</span><span class="p">:</span> <span class="k">pass</span> <span class="n">c</span> <span class="o">=</span> <span class="n">Cls</span><span class="p">()</span> <span class="n">c</span><span class="o">.</span><span class="n">x</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">0</span> <span class="c1"># Annotates c.x with int.</span> <span class="n">c</span><span class="o">.</span><span class="n">y</span><span class="p">:</span> <span class="nb">int</span> <span class="c1"># Annotates c.y with int.</span> <span class="n">d</span> <span class="o">=</span> <span class="p">{}</span> <span class="n">d</span><span class="p">[</span><span class="s1">'a'</span><span class="p">]:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">0</span> <span class="c1"># Annotates d['a'] with int.</span> <span class="n">d</span><span class="p">[</span><span class="s1">'b'</span><span class="p">]:</span> <span class="nb">int</span> <span class="c1"># Annotates d['b'] with int.</span> </pre></div> </div> <p>Note that even a parenthesized name is considered an expression, not a simple name:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">(</span><span class="n">x</span><span class="p">):</span> <span class="nb">int</span> <span class="c1"># Annotates x with int, (x) treated as expression by compiler.</span> <span class="p">(</span><span class="n">y</span><span class="p">):</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">0</span> <span class="c1"># Same situation here.</span> </pre></div> </div> </section> <section id="where-annotations-aren-t-allowed"> <h3><a class="toc-backref" href="#where-annotations-aren-t-allowed" role="doc-backlink">Where annotations aren’t allowed</a></h3> <p>It is illegal to attempt to annotate variables subject to <code class="docutils literal notranslate"><span class="pre">global</span></code> or <code class="docutils literal notranslate"><span class="pre">nonlocal</span></code> in the same function scope:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">f</span><span class="p">():</span> <span class="k">global</span> <span class="n">x</span><span class="p">:</span> <span class="nb">int</span> <span class="c1"># SyntaxError</span> <span class="k">def</span><span class="w"> </span><span class="nf">g</span><span class="p">():</span> <span class="n">x</span><span class="p">:</span> <span class="nb">int</span> <span class="c1"># Also a SyntaxError</span> <span class="k">global</span> <span class="n">x</span> </pre></div> </div> <p>The reason is that <code class="docutils literal notranslate"><span class="pre">global</span></code> and <code class="docutils literal notranslate"><span class="pre">nonlocal</span></code> don’t own variables; therefore, the type annotations belong in the scope owning the variable.</p> <p>Only single assignment targets and single right hand side values are allowed. In addition, one cannot annotate variables used in a <code class="docutils literal notranslate"><span class="pre">for</span></code> or <code class="docutils literal notranslate"><span class="pre">with</span></code> statement; they can be annotated ahead of time, in a similar manner to tuple unpacking:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">a</span><span class="p">:</span> <span class="nb">int</span> <span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">my_iter</span><span class="p">:</span> <span class="o">...</span> <span class="n">f</span><span class="p">:</span> <span class="n">MyFile</span> <span class="k">with</span> <span class="n">myfunc</span><span class="p">()</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span> <span class="o">...</span> </pre></div> </div> </section> <section id="variable-annotations-in-stub-files"> <h3><a class="toc-backref" href="#variable-annotations-in-stub-files" role="doc-backlink">Variable annotations in stub files</a></h3> <p>As variable annotations are more readable than type comments, they are preferred in stub files for all versions of Python, including Python 2.7. Note that stub files are not executed by Python interpreters, and therefore using variable annotations will not lead to errors. Type checkers should support variable annotations in stubs for all versions of Python. For example:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># file lib.pyi</span> <span class="n">ADDRESS</span><span class="p">:</span> <span class="n">unicode</span> <span class="o">=</span> <span class="o">...</span> <span class="k">class</span><span class="w"> </span><span class="nc">Error</span><span class="p">:</span> <span class="n">cause</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">unicode</span><span class="p">]</span> </pre></div> </div> </section> <section id="preferred-coding-style-for-variable-annotations"> <h3><a class="toc-backref" href="#preferred-coding-style-for-variable-annotations" role="doc-backlink">Preferred coding style for variable annotations</a></h3> <p>Annotations for module level variables, class and instance variables, and local variables should have a single space after corresponding colon. There should be no space before the colon. If an assignment has right hand side, then the equality sign should have exactly one space on both sides. Examples:</p> <ul> <li>Yes:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">code</span><span class="p">:</span> <span class="nb">int</span> <span class="k">class</span><span class="w"> </span><span class="nc">Point</span><span class="p">:</span> <span class="n">coords</span><span class="p">:</span> <span class="n">Tuple</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">int</span><span class="p">]</span> <span class="n">label</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s1">'<unknown>'</span> </pre></div> </div> </li> <li>No:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">code</span><span class="p">:</span><span class="nb">int</span> <span class="c1"># No space after colon</span> <span class="n">code</span> <span class="p">:</span> <span class="nb">int</span> <span class="c1"># Space before colon</span> <span class="k">class</span><span class="w"> </span><span class="nc">Test</span><span class="p">:</span> <span class="n">result</span><span class="p">:</span> <span class="nb">int</span><span class="o">=</span><span class="mi">0</span> <span class="c1"># No spaces around equality sign</span> </pre></div> </div> </li> </ul> </section> </section> <section id="changes-to-standard-library-and-documentation"> <h2><a class="toc-backref" href="#changes-to-standard-library-and-documentation" role="doc-backlink">Changes to Standard Library and Documentation</a></h2> <ul class="simple"> <li>A new covariant type <code class="docutils literal notranslate"><span class="pre">ClassVar[T_co]</span></code> is added to the <code class="docutils literal notranslate"><span class="pre">typing</span></code> module. It accepts only a single argument that should be a valid type, and is used to annotate class variables that should not be set on class instances. This restriction is ensured by static checkers, but not at runtime. See the <a class="reference internal" href="#classvar">classvar</a> section for examples and explanations for the usage of <code class="docutils literal notranslate"><span class="pre">ClassVar</span></code>, and see the <a class="reference internal" href="#pep-526-rejected">rejected</a> section for more information on the reasoning behind <code class="docutils literal notranslate"><span class="pre">ClassVar</span></code>.</li> <li>Function <code class="docutils literal notranslate"><span class="pre">get_type_hints</span></code> in the <code class="docutils literal notranslate"><span class="pre">typing</span></code> module will be extended, so that one can retrieve type annotations at runtime from modules and classes as well as functions. Annotations are returned as a dictionary mapping from variable or arguments to their type hints with forward references evaluated. For classes it returns a mapping (perhaps <code class="docutils literal notranslate"><span class="pre">collections.ChainMap</span></code>) constructed from annotations in method resolution order.</li> <li>Recommended guidelines for using annotations will be added to the documentation, containing a pedagogical recapitulation of specifications described in this PEP and in <a class="pep reference internal" href="../pep-0484/" title="PEP 484 – Type Hints">PEP 484</a>. In addition, a helper script for translating type comments into type annotations will be published separately from the standard library.</li> </ul> </section> <section id="runtime-effects-of-type-annotations"> <h2><a class="toc-backref" href="#runtime-effects-of-type-annotations" role="doc-backlink">Runtime Effects of Type Annotations</a></h2> <p>Annotating a local variable will cause the interpreter to treat it as a local, even if it was never assigned to. Annotations for local variables will not be evaluated:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">f</span><span class="p">():</span> <span class="n">x</span><span class="p">:</span> <span class="n">NonexistentName</span> <span class="c1"># No error.</span> </pre></div> </div> <p>However, if it is at a module or class level, then the type <em>will</em> be evaluated:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">x</span><span class="p">:</span> <span class="n">NonexistentName</span> <span class="c1"># Error!</span> <span class="k">class</span><span class="w"> </span><span class="nc">X</span><span class="p">:</span> <span class="n">var</span><span class="p">:</span> <span class="n">NonexistentName</span> <span class="c1"># Error!</span> </pre></div> </div> <p>In addition, at the module or class level, if the item being annotated is a <em>simple name</em>, then it and the annotation will be stored in the <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> attribute of that module or class (mangled if private) as an ordered mapping from names to evaluated annotations. Here is an example:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Dict</span> <span class="k">class</span><span class="w"> </span><span class="nc">Player</span><span class="p">:</span> <span class="o">...</span> <span class="n">players</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Player</span><span class="p">]</span> <span class="n">__points</span><span class="p">:</span> <span class="nb">int</span> <span class="nb">print</span><span class="p">(</span><span class="vm">__annotations__</span><span class="p">)</span> <span class="c1"># prints: {'players': typing.Dict[str, __main__.Player],</span> <span class="c1"># '_Player__points': <class 'int'>}</span> </pre></div> </div> <p><code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> is writable, so this is permitted:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="vm">__annotations__</span><span class="p">[</span><span class="s1">'s'</span><span class="p">]</span> <span class="o">=</span> <span class="nb">str</span> </pre></div> </div> <p>But attempting to update <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> to something other than an ordered mapping may result in a TypeError:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">C</span><span class="p">:</span> <span class="vm">__annotations__</span> <span class="o">=</span> <span class="mi">42</span> <span class="n">x</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">5</span> <span class="c1"># raises TypeError</span> </pre></div> </div> <p>(Note that the assignment to <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code>, which is the culprit, is accepted by the Python interpreter without questioning it – but the subsequent type annotation expects it to be a <code class="docutils literal notranslate"><span class="pre">MutableMapping</span></code> and will fail.)</p> <p>The recommended way of getting annotations at runtime is by using <code class="docutils literal notranslate"><span class="pre">typing.get_type_hints</span></code> function; as with all dunder attributes, any undocumented use of <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> is subject to breakage without warning:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Dict</span><span class="p">,</span> <span class="n">ClassVar</span><span class="p">,</span> <span class="n">get_type_hints</span> <span class="k">class</span><span class="w"> </span><span class="nc">Starship</span><span class="p">:</span> <span class="n">hitpoints</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">50</span> <span class="n">stats</span><span class="p">:</span> <span class="n">ClassVar</span><span class="p">[</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">int</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span> <span class="n">shield</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">100</span> <span class="n">captain</span><span class="p">:</span> <span class="nb">str</span> <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">captain</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span> <span class="o">...</span> <span class="k">assert</span> <span class="n">get_type_hints</span><span class="p">(</span><span class="n">Starship</span><span class="p">)</span> <span class="o">==</span> <span class="p">{</span><span class="s1">'hitpoints'</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="s1">'stats'</span><span class="p">:</span> <span class="n">ClassVar</span><span class="p">[</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">int</span><span class="p">]],</span> <span class="s1">'shield'</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="s1">'captain'</span><span class="p">:</span> <span class="nb">str</span><span class="p">}</span> <span class="k">assert</span> <span class="n">get_type_hints</span><span class="p">(</span><span class="n">Starship</span><span class="o">.</span><span class="fm">__init__</span><span class="p">)</span> <span class="o">==</span> <span class="p">{</span><span class="s1">'captain'</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="s1">'return'</span><span class="p">:</span> <span class="kc">None</span><span class="p">}</span> </pre></div> </div> <p>Note that if annotations are not found statically, then the <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> dictionary is not created at all. Also the value of having annotations available locally does not offset the cost of having to create and populate the annotations dictionary on every function call. Therefore, annotations at function level are not evaluated and not stored.</p> <section id="other-uses-of-annotations"> <h3><a class="toc-backref" href="#other-uses-of-annotations" role="doc-backlink">Other uses of annotations</a></h3> <p>While Python with this PEP will not object to:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">alice</span><span class="p">:</span> <span class="s1">'well done'</span> <span class="o">=</span> <span class="s1">'A+'</span> <span class="n">bob</span><span class="p">:</span> <span class="s1">'what a shame'</span> <span class="o">=</span> <span class="s1">'F-'</span> </pre></div> </div> <p>since it will not care about the type annotation beyond “it evaluates without raising”, a type checker that encounters it will flag it, unless disabled with <code class="docutils literal notranslate"><span class="pre">#</span> <span class="pre">type:</span> <span class="pre">ignore</span></code> or <code class="docutils literal notranslate"><span class="pre">@no_type_check</span></code>.</p> <p>However, since Python won’t care what the “type” is, if the above snippet is at the global level or in a class, <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> will include <code class="docutils literal notranslate"><span class="pre">{'alice':</span> <span class="pre">'well</span> <span class="pre">done',</span> <span class="pre">'bob':</span> <span class="pre">'what</span> <span class="pre">a</span> <span class="pre">shame'}</span></code>.</p> <p>These stored annotations might be used for other purposes, but with this PEP we explicitly recommend type hinting as the preferred use of annotations.</p> </section> </section> <section id="rejected-postponed-proposals"> <span id="pep-526-rejected"></span><h2><a class="toc-backref" href="#rejected-postponed-proposals" role="doc-backlink">Rejected/Postponed Proposals</a></h2> <ul> <li><strong>Should we introduce variable annotations at all?</strong> Variable annotations have <em>already</em> been around for almost two years in the form of type comments, sanctioned by <a class="pep reference internal" href="../pep-0484/" title="PEP 484 – Type Hints">PEP 484</a>. They are extensively used by third party type checkers (mypy, pytype, PyCharm, etc.) and by projects using the type checkers. However, the comment syntax has many downsides listed in Rationale. This PEP is not about the need for type annotations, it is about what should be the syntax for such annotations.</li> <li><strong>Introduce a new keyword:</strong> The choice of a good keyword is hard, e.g. it can’t be <code class="docutils literal notranslate"><span class="pre">var</span></code> because that is way too common a variable name, and it can’t be <code class="docutils literal notranslate"><span class="pre">local</span></code> if we want to use it for class variables or globals. Second, no matter what we choose, we’d still need a <code class="docutils literal notranslate"><span class="pre">__future__</span></code> import.</li> <li><strong>Use</strong> <code class="docutils literal notranslate"><span class="pre">def</span></code> <strong>as a keyword:</strong> The proposal would be:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">primes</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="k">def</span><span class="w"> </span><span class="nf">captain</span><span class="p">:</span> <span class="nb">str</span> </pre></div> </div> <p>The problem with this is that <code class="docutils literal notranslate"><span class="pre">def</span></code> means “define a function” to generations of Python programmers (and tools!), and using it also to define variables does not increase clarity. (Though this is of course subjective.)</p> </li> <li><strong>Use function based syntax</strong>: It was proposed to annotate types of variables using <code class="docutils literal notranslate"><span class="pre">var</span> <span class="pre">=</span> <span class="pre">cast(annotation[,</span> <span class="pre">value])</span></code>. Although this syntax alleviates some problems with type comments like absence of the annotation in AST, it does not solve other problems such as readability and it introduces possible runtime overhead.</li> <li><strong>Allow type annotations for tuple unpacking:</strong> This causes ambiguity: it’s not clear what this statement means:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">:</span> <span class="n">T</span> </pre></div> </div> <p>Are <code class="docutils literal notranslate"><span class="pre">x</span></code> and <code class="docutils literal notranslate"><span class="pre">y</span></code> both of type <code class="docutils literal notranslate"><span class="pre">T</span></code>, or do we expect <code class="docutils literal notranslate"><span class="pre">T</span></code> to be a tuple type of two items that are distributed over <code class="docutils literal notranslate"><span class="pre">x</span></code> and <code class="docutils literal notranslate"><span class="pre">y</span></code>, or perhaps <code class="docutils literal notranslate"><span class="pre">x</span></code> has type <code class="docutils literal notranslate"><span class="pre">Any</span></code> and <code class="docutils literal notranslate"><span class="pre">y</span></code> has type <code class="docutils literal notranslate"><span class="pre">T</span></code>? (The latter is what this would mean if this occurred in a function signature.) Rather than leave the (human) reader guessing, we forbid this, at least for now.</p> </li> <li><strong>Parenthesized form</strong> <code class="docutils literal notranslate"><span class="pre">(var:</span> <span class="pre">type)</span></code> <strong>for annotations:</strong> It was brought up on python-ideas as a remedy for the above-mentioned ambiguity, but it was rejected since such syntax would be hairy, the benefits are slight, and the readability would be poor.</li> <li><strong>Allow annotations in chained assignments:</strong> This has problems of ambiguity and readability similar to tuple unpacking, for example in:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">x</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="n">y</span> <span class="o">=</span> <span class="mi">1</span> <span class="n">z</span> <span class="o">=</span> <span class="n">w</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">1</span> </pre></div> </div> <p>it is ambiguous, what should the types of <code class="docutils literal notranslate"><span class="pre">y</span></code> and <code class="docutils literal notranslate"><span class="pre">z</span></code> be? Also the second line is difficult to parse.</p> </li> <li><strong>Allow annotations in</strong> <code class="docutils literal notranslate"><span class="pre">with</span></code> <strong>and</strong> <code class="docutils literal notranslate"><span class="pre">for</span></code> <strong>statement:</strong> This was rejected because in <code class="docutils literal notranslate"><span class="pre">for</span></code> it would make it hard to spot the actual iterable, and in <code class="docutils literal notranslate"><span class="pre">with</span></code> it would confuse the CPython’s LL(1) parser.</li> <li><strong>Evaluate local annotations at function definition time:</strong> This has been rejected by Guido because the placement of the annotation strongly suggests that it’s in the same scope as the surrounding code.</li> <li><strong>Store variable annotations also in function scope:</strong> The value of having the annotations available locally is just not enough to significantly offset the cost of creating and populating the dictionary on <em>each</em> function call.</li> <li><strong>Initialize variables annotated without assignment:</strong> It was proposed on python-ideas to initialize <code class="docutils literal notranslate"><span class="pre">x</span></code> in <code class="docutils literal notranslate"><span class="pre">x:</span> <span class="pre">int</span></code> to <code class="docutils literal notranslate"><span class="pre">None</span></code> or to an additional special constant like Javascript’s <code class="docutils literal notranslate"><span class="pre">undefined</span></code>. However, adding yet another singleton value to the language would needed to be checked for everywhere in the code. Therefore, Guido just said plain “No” to this.</li> <li><strong>Add also</strong> <code class="docutils literal notranslate"><span class="pre">InstanceVar</span></code> <strong>to the typing module:</strong> This is redundant because instance variables are way more common than class variables. The more common usage deserves to be the default.</li> <li><strong>Allow instance variable annotations only in methods:</strong> The problem is that many <code class="docutils literal notranslate"><span class="pre">__init__</span></code> methods do a lot of things besides initializing instance variables, and it would be harder (for a human) to find all the instance variable annotations. And sometimes <code class="docutils literal notranslate"><span class="pre">__init__</span></code> is factored into more helper methods so it’s even harder to chase them down. Putting the instance variable annotations together in the class makes it easier to find them, and helps a first-time reader of the code.</li> <li><strong>Use syntax</strong> <code class="docutils literal notranslate"><span class="pre">x:</span> <span class="pre">class</span> <span class="pre">t</span> <span class="pre">=</span> <span class="pre">v</span></code> <strong>for class variables:</strong> This would require a more complicated parser and the <code class="docutils literal notranslate"><span class="pre">class</span></code> keyword would confuse simple-minded syntax highlighters. Anyway we need to have <code class="docutils literal notranslate"><span class="pre">ClassVar</span></code> store class variables to <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code>, so a simpler syntax was chosen.</li> <li><strong>Forget about</strong> <code class="docutils literal notranslate"><span class="pre">ClassVar</span></code> <strong>altogether:</strong> This was proposed since mypy seems to be getting along fine without a way to distinguish between class and instance variables. But a type checker can do useful things with the extra information, for example flag accidental assignments to a class variable via the instance (which would create an instance variable shadowing the class variable). It could also flag instance variables with mutable defaults, a well-known hazard.</li> <li><strong>Use</strong> <code class="docutils literal notranslate"><span class="pre">ClassAttr</span></code> <strong>instead of</strong> <code class="docutils literal notranslate"><span class="pre">ClassVar</span></code>: The main reason why <code class="docutils literal notranslate"><span class="pre">ClassVar</span></code> is better is following: many things are class attributes, e.g. methods, descriptors, etc. But only specific attributes are conceptually class variables (or maybe constants).</li> <li><strong>Do not evaluate annotations, treat them as strings:</strong> This would be inconsistent with the behavior of function annotations that are always evaluated. Although this might be reconsidered in future, it was decided in <a class="pep reference internal" href="../pep-0484/" title="PEP 484 – Type Hints">PEP 484</a> that this would have to be a separate PEP.</li> <li><strong>Annotate variable types in class docstring:</strong> Many projects already use various docstring conventions, often without much consistency and generally without conforming to the <a class="pep reference internal" href="../pep-0484/" title="PEP 484 – Type Hints">PEP 484</a> annotation syntax yet. Also this would require a special sophisticated parser. This, in turn, would defeat the purpose of the PEP – collaborating with the third party type checking tools.</li> <li><strong>Implement</strong> <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> <strong>as a descriptor:</strong> This was proposed to prohibit setting <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> to something non-dictionary or non-None. Guido has rejected this idea as unnecessary; instead a TypeError will be raised if an attempt is made to update <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> when it is anything other than a mapping.</li> <li><strong>Treating bare annotations the same as global or nonlocal:</strong> The rejected proposal would prefer that the presence of an annotation without assignment in a function body should not involve <em>any</em> evaluation. In contrast, the PEP implies that if the target is more complex than a single name, its “left-hand part” should be evaluated at the point where it occurs in the function body, just to enforce that it is defined. For example, in this example:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">foo</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="n">slef</span><span class="o">.</span><span class="n">name</span><span class="p">:</span> <span class="nb">str</span> </pre></div> </div> <p>the name <code class="docutils literal notranslate"><span class="pre">slef</span></code> should be evaluated, just so that if it is not defined (as is likely in this example :-), the error will be caught at runtime. This is more in line with what happens when there <em>is</em> an initial value, and thus is expected to lead to fewer surprises. (Also note that if the target was <code class="docutils literal notranslate"><span class="pre">self.name</span></code> (this time correctly spelled :-), an optimizing compiler has no obligation to evaluate <code class="docutils literal notranslate"><span class="pre">self</span></code> as long as it can prove that it will definitely be defined.)</p> </li> </ul> </section> <section id="backwards-compatibility"> <h2><a class="toc-backref" href="#backwards-compatibility" role="doc-backlink">Backwards Compatibility</a></h2> <p>This PEP is fully backwards compatible.</p> </section> <section id="implementation"> <h2><a class="toc-backref" href="#implementation" role="doc-backlink">Implementation</a></h2> <p>An implementation for Python 3.6 can be found <a class="reference external" href="https://github.com/python/cpython/commit/f8cb8a16a3">on GitHub</a>.</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-0526.rst">https://github.com/python/peps/blob/main/peps/pep-0526.rst</a></p> <p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0526.rst">2025-02-01 08:59:27 GMT</a></p> </article> <nav id="pep-sidebar"> <h2>Contents</h2> <ul> <li><a class="reference internal" href="#status">Status</a></li> <li><a class="reference internal" href="#notice-for-reviewers">Notice for Reviewers</a></li> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#rationale">Rationale</a><ul> <li><a class="reference internal" href="#non-goals">Non-goals</a></li> </ul> </li> <li><a class="reference internal" href="#specification">Specification</a><ul> <li><a class="reference internal" href="#global-and-local-variable-annotations">Global and local variable annotations</a></li> <li><a class="reference internal" href="#class-and-instance-variable-annotations">Class and instance variable annotations</a></li> <li><a class="reference internal" href="#annotating-expressions">Annotating expressions</a></li> <li><a class="reference internal" href="#where-annotations-aren-t-allowed">Where annotations aren’t allowed</a></li> <li><a class="reference internal" href="#variable-annotations-in-stub-files">Variable annotations in stub files</a></li> <li><a class="reference internal" href="#preferred-coding-style-for-variable-annotations">Preferred coding style for variable annotations</a></li> </ul> </li> <li><a class="reference internal" href="#changes-to-standard-library-and-documentation">Changes to Standard Library and Documentation</a></li> <li><a class="reference internal" href="#runtime-effects-of-type-annotations">Runtime Effects of Type Annotations</a><ul> <li><a class="reference internal" href="#other-uses-of-annotations">Other uses of annotations</a></li> </ul> </li> <li><a class="reference internal" href="#rejected-postponed-proposals">Rejected/Postponed Proposals</a></li> <li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a></li> <li><a class="reference internal" href="#implementation">Implementation</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-0526.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>