python-peps/pep-0563/index.html

780 lines
64 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

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

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="color-scheme" content="light dark">
<title>PEP 563 Postponed Evaluation of Annotations | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-0563/">
<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 563 Postponed Evaluation of Annotations | peps.python.org'>
<meta property="og:description" content="PEP 3107 introduced syntax for function annotations, but the semantics were deliberately left undefined. PEP 484 introduced a standard meaning to annotations: type hints. PEP 526 defined variable annotations, explicitly tying them with the type hintin...">
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-0563/">
<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 3107 introduced syntax for function annotations, but the semantics were deliberately left undefined. PEP 484 introduced a standard meaning to annotations: type hints. PEP 526 defined variable annotations, explicitly tying them with the type hintin...">
<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 563</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 563 Postponed Evaluation of Annotations</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Łukasz Langa &lt;lukasz&#32;&#97;t&#32;python.org&gt;</dd>
<dt class="field-even">Discussions-To<span class="colon">:</span></dt>
<dd class="field-even"><a class="reference external" href="https://mail.python.org/archives/list/python-dev&#64;python.org/">Python-Dev list</a></dd>
<dt class="field-odd">Status<span class="colon">:</span></dt>
<dd class="field-odd"><abbr title="Normative proposal accepted for implementation">Accepted</abbr></dd>
<dt class="field-even">Type<span class="colon">:</span></dt>
<dd class="field-even"><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-odd">Topic<span class="colon">:</span></dt>
<dd class="field-odd"><a class="reference external" href="../topic/typing/">Typing</a></dd>
<dt class="field-even">Created<span class="colon">:</span></dt>
<dd class="field-even">08-Sep-2017</dd>
<dt class="field-odd">Python-Version<span class="colon">:</span></dt>
<dd class="field-odd">3.7</dd>
<dt class="field-even">Post-History<span class="colon">:</span></dt>
<dd class="field-even">01-Nov-2017, 21-Nov-2017</dd>
<dt class="field-odd">Superseded-By<span class="colon">:</span></dt>
<dd class="field-odd"><a class="reference external" href="../pep-0649/">649</a></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/2017-December/151042.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="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#rationale-and-goals">Rationale and Goals</a><ul>
<li><a class="reference internal" href="#non-goals">Non-goals</a></li>
<li><a class="reference internal" href="#non-typing-usage-of-annotations">Non-typing usage of annotations</a></li>
</ul>
</li>
<li><a class="reference internal" href="#implementation">Implementation</a><ul>
<li><a class="reference internal" href="#enabling-the-future-behavior-in-python-3-7">Enabling the future behavior in Python 3.7</a></li>
</ul>
</li>
<li><a class="reference internal" href="#resolving-type-hints-at-runtime">Resolving Type Hints at Runtime</a><ul>
<li><a class="reference internal" href="#runtime-annotation-resolution-and-class-decorators">Runtime annotation resolution and class decorators</a></li>
<li><a class="reference internal" href="#runtime-annotation-resolution-and-type-checking">Runtime annotation resolution and <code class="docutils literal notranslate"><span class="pre">TYPE_CHECKING</span></code></a></li>
</ul>
</li>
<li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a><ul>
<li><a class="reference internal" href="#deprecation-policy">Deprecation policy</a></li>
</ul>
</li>
<li><a class="reference internal" href="#forward-references">Forward References</a></li>
<li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul>
<li><a class="reference internal" href="#keeping-the-ability-to-use-function-local-state-when-defining-annotations">Keeping the ability to use function local state when defining annotations</a></li>
<li><a class="reference internal" href="#disallowing-local-state-usage-for-classes-too">Disallowing local state usage for classes, too</a></li>
<li><a class="reference internal" href="#introducing-a-new-dictionary-for-the-string-literal-form-instead">Introducing a new dictionary for the string literal form instead</a></li>
<li><a class="reference internal" href="#dropping-annotations-with-o">Dropping annotations with -O</a></li>
<li><a class="reference internal" href="#passing-string-literals-in-annotations-verbatim-to-annotations">Passing string literals in annotations verbatim to <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code></a></li>
<li><a class="reference internal" href="#making-the-name-of-the-future-import-more-verbose">Making the name of the future import more verbose</a></li>
</ul>
</li>
<li><a class="reference internal" href="#prior-discussion">Prior discussion</a><ul>
<li><a class="reference internal" href="#in-pep-484">In PEP 484</a></li>
<li><a class="reference internal" href="#python-typing-400">python/typing#400</a></li>
<li><a class="reference internal" href="#first-draft-discussion-on-python-ideas">First draft discussion on python-ideas</a></li>
<li><a class="reference internal" href="#second-draft-discussion-on-python-dev">Second draft discussion on python-dev</a></li>
</ul>
</li>
<li><a class="reference internal" href="#acknowledgements">Acknowledgements</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
</details></section>
<section id="abstract">
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
<p><a class="pep reference internal" href="../pep-3107/" title="PEP 3107 Function Annotations">PEP 3107</a> introduced syntax for function annotations, but the semantics
were deliberately left undefined. <a class="pep reference internal" href="../pep-0484/" title="PEP 484 Type Hints">PEP 484</a> introduced a standard meaning
to annotations: type hints. <a class="pep reference internal" href="../pep-0526/" title="PEP 526 Syntax for Variable Annotations">PEP 526</a> defined variable annotations,
explicitly tying them with the type hinting use case.</p>
<p>This PEP proposes changing function annotations and variable annotations
so that they are no longer evaluated at function definition time.
Instead, they are preserved in <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> in string form.</p>
<p>This change is being introduced gradually, starting with a
<code class="docutils literal notranslate"><span class="pre">__future__</span></code> import in Python 3.7.</p>
</section>
<section id="rationale-and-goals">
<h2><a class="toc-backref" href="#rationale-and-goals" role="doc-backlink">Rationale and Goals</a></h2>
<p><a class="pep reference internal" href="../pep-3107/" title="PEP 3107 Function Annotations">PEP 3107</a> added support for arbitrary annotations on parts of a function
definition. Just like default values, annotations are evaluated at
function definition time. This creates a number of issues for the type
hinting use case:</p>
<ul class="simple">
<li>forward references: when a type hint contains names that have not been
defined yet, that definition needs to be expressed as a string
literal;</li>
<li>type hints are executed at module import time, which is not
computationally free.</li>
</ul>
<p>Postponing the evaluation of annotations solves both problems.
NOTE: <a class="pep reference internal" href="../pep-0649/" title="PEP 649 Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a> proposes an alternative solution to the above issues,
putting this PEP in danger of being superseded.</p>
<section id="non-goals">
<h3><a class="toc-backref" href="#non-goals" role="doc-backlink">Non-goals</a></h3>
<p>Just like in <a class="pep reference internal" href="../pep-0484/" title="PEP 484 Type Hints">PEP 484</a> and <a class="pep reference internal" href="../pep-0526/" title="PEP 526 Syntax for Variable Annotations">PEP 526</a>, it should 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></p>
<p>This PEP is meant to solve the problem of forward references in type
annotations. There are still cases outside of annotations where
forward references will require usage of string literals. Those are
listed in a later section of this document.</p>
<p>Annotations without forced evaluation enable opportunities to improve
the syntax of type hints. This idea will require its own separate PEP
and is not discussed further in this document.</p>
</section>
<section id="non-typing-usage-of-annotations">
<h3><a class="toc-backref" href="#non-typing-usage-of-annotations" role="doc-backlink">Non-typing usage of annotations</a></h3>
<p>While annotations are still available for arbitrary use besides type
checking, it is worth mentioning that the design of this PEP, as well
as its precursors (<a class="pep reference internal" href="../pep-0484/" title="PEP 484 Type Hints">PEP 484</a> and <a class="pep reference internal" href="../pep-0526/" title="PEP 526 Syntax for Variable Annotations">PEP 526</a>), is predominantly motivated by
the type hinting use case.</p>
<p>In Python 3.8 <a class="pep reference internal" href="../pep-0484/" title="PEP 484 Type Hints">PEP 484</a> will graduate from provisional status. Other
enhancements to the Python programming language like <a class="pep reference internal" href="../pep-0544/" title="PEP 544 Protocols: Structural subtyping (static duck typing)">PEP 544</a>, <a class="pep reference internal" href="../pep-0557/" title="PEP 557 Data Classes">PEP 557</a>,
or <a class="pep reference internal" href="../pep-0560/" title="PEP 560 Core support for typing module and generic types">PEP 560</a>, are already being built on this basis as they depend on
type annotations and the <code class="docutils literal notranslate"><span class="pre">typing</span></code> module as defined by <a class="pep reference internal" href="../pep-0484/" title="PEP 484 Type Hints">PEP 484</a>.
In fact, the reason <a class="pep reference internal" href="../pep-0484/" title="PEP 484 Type Hints">PEP 484</a> is staying provisional in Python 3.7 is to
enable rapid evolution for another release cycle that some of the
aforementioned enhancements require.</p>
<p>With this in mind, uses for annotations incompatible with the
aforementioned PEPs should be considered deprecated.</p>
</section>
</section>
<section id="implementation">
<h2><a class="toc-backref" href="#implementation" role="doc-backlink">Implementation</a></h2>
<p>With this PEP, function and variable annotations will no longer be
evaluated at definition time. Instead, a string form will be preserved
in the respective <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> dictionary. Static type checkers
will see no difference in behavior, whereas tools using annotations at
runtime will have to perform postponed evaluation.</p>
<p>The string form is obtained from the AST during the compilation step,
which means that the string form might not preserve the exact formatting
of the source. Note: if an annotation was a string literal already, it
will still be wrapped in a string.</p>
<p>Annotations need to be syntactically valid Python expressions, also when
passed as literal strings (i.e. <code class="docutils literal notranslate"><span class="pre">compile(literal,</span> <span class="pre">'',</span> <span class="pre">'eval')</span></code>).
Annotations can only use names present in the module scope as postponed
evaluation using local names is not reliable (with the sole exception of
class-level names resolved by <code class="docutils literal notranslate"><span class="pre">typing.get_type_hints()</span></code>).</p>
<p>Note that as per <a class="pep reference internal" href="../pep-0526/" title="PEP 526 Syntax for Variable Annotations">PEP 526</a>, local variable annotations are not evaluated
at all since they are not accessible outside of the functions closure.</p>
<section id="enabling-the-future-behavior-in-python-3-7">
<h3><a class="toc-backref" href="#enabling-the-future-behavior-in-python-3-7" role="doc-backlink">Enabling the future behavior in Python 3.7</a></h3>
<p>The functionality described above can be enabled starting from Python
3.7 using the following special import:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">annotations</span>
</pre></div>
</div>
<p>A reference implementation of this functionality is available
<a class="reference external" href="https://github.com/python/cpython/pull/4390">on GitHub</a>.</p>
</section>
</section>
<section id="resolving-type-hints-at-runtime">
<h2><a class="toc-backref" href="#resolving-type-hints-at-runtime" role="doc-backlink">Resolving Type Hints at Runtime</a></h2>
<p>To resolve an annotation at runtime from its string form to the result
of the enclosed expression, user code needs to evaluate the string.</p>
<p>For code that uses type hints, the
<code class="docutils literal notranslate"><span class="pre">typing.get_type_hints(obj,</span> <span class="pre">globalns=None,</span> <span class="pre">localns=None)</span></code> function
correctly evaluates expressions back from its string form. Note that
all valid code currently using <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> should already be
doing that since a type annotation can be expressed as a string literal.</p>
<p>For code which uses annotations for other purposes, a regular
<code class="docutils literal notranslate"><span class="pre">eval(ann,</span> <span class="pre">globals,</span> <span class="pre">locals)</span></code> call is enough to resolve the
annotation.</p>
<p>In both cases its important to consider how globals and locals affect
the postponed evaluation. An annotation is no longer evaluated at the
time of definition and, more importantly, <em>in the same scope</em> where it
was defined. Consequently, using local state in annotations is no
longer possible in general. As for globals, the module where the
annotation was defined is the correct context for postponed evaluation.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">get_type_hints()</span></code> function automatically resolves the correct
value of <code class="docutils literal notranslate"><span class="pre">globalns</span></code> for functions and classes. It also automatically
provides the correct <code class="docutils literal notranslate"><span class="pre">localns</span></code> for classes.</p>
<p>When running <code class="docutils literal notranslate"><span class="pre">eval()</span></code>,
the value of globals can be gathered in the following way:</p>
<ul>
<li>function objects hold a reference to their respective globals in an
attribute called <code class="docutils literal notranslate"><span class="pre">__globals__</span></code>;</li>
<li>classes hold the name of the module they were defined in, this can be
used to retrieve the respective globals:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">cls_globals</span> <span class="o">=</span> <span class="nb">vars</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">modules</span><span class="p">[</span><span class="n">SomeClass</span><span class="o">.</span><span class="vm">__module__</span><span class="p">])</span>
</pre></div>
</div>
<p>Note that this needs to be repeated for base classes to evaluate all
<code class="docutils literal notranslate"><span class="pre">__annotations__</span></code>.</p>
</li>
<li>modules should use their own <code class="docutils literal notranslate"><span class="pre">__dict__</span></code>.</li>
</ul>
<p>The value of <code class="docutils literal notranslate"><span class="pre">localns</span></code> cannot be reliably retrieved for functions
because in all likelihood the stack frame at the time of the call no
longer exists.</p>
<p>For classes, <code class="docutils literal notranslate"><span class="pre">localns</span></code> can be composed by chaining vars of the given
class and its base classes (in the method resolution order). Since slots
can only be filled after the class was defined, we dont need to consult
them for this purpose.</p>
<section id="runtime-annotation-resolution-and-class-decorators">
<h3><a class="toc-backref" href="#runtime-annotation-resolution-and-class-decorators" role="doc-backlink">Runtime annotation resolution and class decorators</a></h3>
<p>Metaclasses and class decorators that need to resolve annotations for
the current class will fail for annotations that use the name of the
current class. Example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">class_decorator</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
<span class="n">annotations</span> <span class="o">=</span> <span class="n">get_type_hints</span><span class="p">(</span><span class="bp">cls</span><span class="p">)</span> <span class="c1"># raises NameError on &#39;C&#39;</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;Annotations for </span><span class="si">{</span><span class="bp">cls</span><span class="si">}</span><span class="s1">: </span><span class="si">{</span><span class="n">annotations</span><span class="si">}</span><span class="s1">&#39;</span><span class="p">)</span>
<span class="k">return</span> <span class="bp">cls</span>
<span class="nd">@class_decorator</span>
<span class="k">class</span> <span class="nc">C</span><span class="p">:</span>
<span class="n">singleton</span><span class="p">:</span> <span class="s1">&#39;C&#39;</span> <span class="o">=</span> <span class="kc">None</span>
</pre></div>
</div>
<p>This was already true before this PEP. The class decorator acts on
the class before its assigned a name in the current definition scope.</p>
</section>
<section id="runtime-annotation-resolution-and-type-checking">
<h3><a class="toc-backref" href="#runtime-annotation-resolution-and-type-checking" role="doc-backlink">Runtime annotation resolution and <code class="docutils literal notranslate"><span class="pre">TYPE_CHECKING</span></code></a></h3>
<p>Sometimes theres code that must be seen by a type checker but should
not be executed. For such situations the <code class="docutils literal notranslate"><span class="pre">typing</span></code> module defines a
constant, <code class="docutils literal notranslate"><span class="pre">TYPE_CHECKING</span></code>, that is considered <code class="docutils literal notranslate"><span class="pre">True</span></code> during type
checking but <code class="docutils literal notranslate"><span class="pre">False</span></code> at runtime. Example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">typing</span>
<span class="k">if</span> <span class="n">typing</span><span class="o">.</span><span class="n">TYPE_CHECKING</span><span class="p">:</span>
<span class="kn">import</span> <span class="nn">expensive_mod</span>
<span class="k">def</span> <span class="nf">a_func</span><span class="p">(</span><span class="n">arg</span><span class="p">:</span> <span class="n">expensive_mod</span><span class="o">.</span><span class="n">SomeClass</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">a_var</span><span class="p">:</span> <span class="n">expensive_mod</span><span class="o">.</span><span class="n">SomeClass</span> <span class="o">=</span> <span class="n">arg</span>
<span class="o">...</span>
</pre></div>
</div>
<p>This approach is also useful when handling import cycles.</p>
<p>Trying to resolve annotations of <code class="docutils literal notranslate"><span class="pre">a_func</span></code> at runtime using
<code class="docutils literal notranslate"><span class="pre">typing.get_type_hints()</span></code> will fail since the name <code class="docutils literal notranslate"><span class="pre">expensive_mod</span></code>
is not defined (<code class="docutils literal notranslate"><span class="pre">TYPE_CHECKING</span></code> variable being <code class="docutils literal notranslate"><span class="pre">False</span></code> at runtime).
This was already true before this PEP.</p>
</section>
</section>
<section id="backwards-compatibility">
<h2><a class="toc-backref" href="#backwards-compatibility" role="doc-backlink">Backwards Compatibility</a></h2>
<p>This is a backwards incompatible change. Applications depending on
arbitrary objects to be directly present in annotations will break
if they are not using <code class="docutils literal notranslate"><span class="pre">typing.get_type_hints()</span></code> or <code class="docutils literal notranslate"><span class="pre">eval()</span></code>.</p>
<p>Annotations that depend on locals at the time of the function
definition will not be resolvable later. Example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">generate</span><span class="p">():</span>
<span class="n">A</span> <span class="o">=</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">int</span><span class="p">]</span>
<span class="k">class</span> <span class="nc">C</span><span class="p">:</span>
<span class="n">field</span><span class="p">:</span> <span class="n">A</span> <span class="o">=</span> <span class="mi">1</span>
<span class="k">def</span> <span class="nf">method</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">arg</span><span class="p">:</span> <span class="n">A</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">return</span> <span class="n">C</span>
<span class="n">X</span> <span class="o">=</span> <span class="n">generate</span><span class="p">()</span>
</pre></div>
</div>
<p>Trying to resolve annotations of <code class="docutils literal notranslate"><span class="pre">X</span></code> later by using
<code class="docutils literal notranslate"><span class="pre">get_type_hints(X)</span></code> will fail because <code class="docutils literal notranslate"><span class="pre">A</span></code> and its enclosing scope no
longer exists. Python will make no attempt to disallow such annotations
since they can often still be successfully statically analyzed, which is
the predominant use case for annotations.</p>
<p>Annotations using nested classes and their respective state are still
valid. They can use local names or the fully qualified name. Example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">C</span><span class="p">:</span>
<span class="n">field</span> <span class="o">=</span> <span class="s1">&#39;c_field&#39;</span>
<span class="k">def</span> <span class="nf">method</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">C</span><span class="o">.</span><span class="n">field</span><span class="p">:</span> <span class="c1"># this is OK</span>
<span class="o">...</span>
<span class="k">def</span> <span class="nf">method</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">field</span><span class="p">:</span> <span class="c1"># this is OK</span>
<span class="o">...</span>
<span class="k">def</span> <span class="nf">method</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">C</span><span class="o">.</span><span class="n">D</span><span class="p">:</span> <span class="c1"># this is OK</span>
<span class="o">...</span>
<span class="k">def</span> <span class="nf">method</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">D</span><span class="p">:</span> <span class="c1"># this is OK</span>
<span class="o">...</span>
<span class="k">class</span> <span class="nc">D</span><span class="p">:</span>
<span class="n">field2</span> <span class="o">=</span> <span class="s1">&#39;d_field&#39;</span>
<span class="k">def</span> <span class="nf">method</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">C</span><span class="o">.</span><span class="n">D</span><span class="o">.</span><span class="n">field2</span><span class="p">:</span> <span class="c1"># this is OK</span>
<span class="o">...</span>
<span class="k">def</span> <span class="nf">method</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">D</span><span class="o">.</span><span class="n">field2</span><span class="p">:</span> <span class="c1"># this FAILS, class D is local to C</span>
<span class="o">...</span> <span class="c1"># and is therefore only available</span>
<span class="c1"># as C.D. This was already true</span>
<span class="c1"># before the PEP.</span>
<span class="k">def</span> <span class="nf">method</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">field2</span><span class="p">:</span> <span class="c1"># this is OK</span>
<span class="o">...</span>
<span class="k">def</span> <span class="nf">method</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">field</span><span class="p">:</span> <span class="c1"># this FAILS, field is local to C and</span>
<span class="c1"># is therefore not visible to D unless</span>
<span class="c1"># accessed as C.field. This was already</span>
<span class="c1"># true before the PEP.</span>
</pre></div>
</div>
<p>In the presence of an annotation that isnt a syntactically valid
expression, SyntaxError is raised at compile time. However, since names
arent resolved at that time, no attempt is made to validate whether
used names are correct or not.</p>
<section id="deprecation-policy">
<h3><a class="toc-backref" href="#deprecation-policy" role="doc-backlink">Deprecation policy</a></h3>
<p>Starting with Python 3.7, a <code class="docutils literal notranslate"><span class="pre">__future__</span></code> import is required to use the
described functionality. No warnings are raised.</p>
<p>NOTE: Whether this will eventually become the default behavior is currently unclear
pending decision on <a class="pep reference internal" href="../pep-0649/" title="PEP 649 Deferred Evaluation Of Annotations Using Descriptors">PEP 649</a>. In any case, use of annotations that depend upon
their eager evaluation is incompatible with both proposals and is no longer
supported.</p>
</section>
</section>
<section id="forward-references">
<h2><a class="toc-backref" href="#forward-references" role="doc-backlink">Forward References</a></h2>
<p>Deliberately using a name before it was defined in the module is called
a forward reference. For the purpose of this section, well call
any name imported or defined within a <code class="docutils literal notranslate"><span class="pre">if</span> <span class="pre">TYPE_CHECKING:</span></code> block
a forward reference, too.</p>
<p>This PEP addresses the issue of forward references in <em>type annotations</em>.
The use of string literals will no longer be required in this case.
However, there are APIs in the <code class="docutils literal notranslate"><span class="pre">typing</span></code> module that use other syntactic
constructs of the language, and those will still require working around
forward references with string literals. The list includes:</p>
<ul>
<li>type definitions:<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">bound</span><span class="o">=</span><span class="s1">&#39;&lt;type&gt;&#39;</span><span class="p">)</span>
<span class="n">UserId</span> <span class="o">=</span> <span class="n">NewType</span><span class="p">(</span><span class="s1">&#39;UserId&#39;</span><span class="p">,</span> <span class="s1">&#39;&lt;type&gt;&#39;</span><span class="p">)</span>
<span class="n">Employee</span> <span class="o">=</span> <span class="n">NamedTuple</span><span class="p">(</span><span class="s1">&#39;Employee&#39;</span><span class="p">,</span> <span class="p">[(</span><span class="s1">&#39;name&#39;</span><span class="p">,</span> <span class="s1">&#39;&lt;type&gt;&#39;</span><span class="p">),</span> <span class="p">(</span><span class="s1">&#39;id&#39;</span><span class="p">,</span> <span class="s1">&#39;&lt;type&gt;&#39;</span><span class="p">)])</span>
</pre></div>
</div>
</li>
<li>aliases:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Alias</span> <span class="o">=</span> <span class="n">Optional</span><span class="p">[</span><span class="s1">&#39;&lt;type&gt;&#39;</span><span class="p">]</span>
<span class="n">AnotherAlias</span> <span class="o">=</span> <span class="n">Union</span><span class="p">[</span><span class="s1">&#39;&lt;type&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;&lt;type&gt;&#39;</span><span class="p">]</span>
<span class="n">YetAnotherAlias</span> <span class="o">=</span> <span class="s1">&#39;&lt;type&gt;&#39;</span>
</pre></div>
</div>
</li>
<li>casting:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">cast</span><span class="p">(</span><span class="s1">&#39;&lt;type&gt;&#39;</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
</pre></div>
</div>
</li>
<li>base classes:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">C</span><span class="p">(</span><span class="n">Tuple</span><span class="p">[</span><span class="s1">&#39;&lt;type&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;&lt;type&gt;&#39;</span><span class="p">]):</span> <span class="o">...</span>
</pre></div>
</div>
</li>
</ul>
<p>Depending on the specific case, some of the cases listed above might be
worked around by placing the usage in a <code class="docutils literal notranslate"><span class="pre">if</span> <span class="pre">TYPE_CHECKING:</span></code> block.
This will not work for any code that needs to be available at runtime,
notably for base classes and casting. For named tuples, using the new
class definition syntax introduced in Python 3.6 solves the issue.</p>
<p>In general, fixing the issue for <em>all</em> forward references requires
changing how module instantiation is performed in Python, from the
current single-pass top-down model. This would be a major change in the
language and is out of scope for this PEP.</p>
</section>
<section id="rejected-ideas">
<h2><a class="toc-backref" href="#rejected-ideas" role="doc-backlink">Rejected Ideas</a></h2>
<section id="keeping-the-ability-to-use-function-local-state-when-defining-annotations">
<h3><a class="toc-backref" href="#keeping-the-ability-to-use-function-local-state-when-defining-annotations" role="doc-backlink">Keeping the ability to use function local state when defining annotations</a></h3>
<p>With postponed evaluation, this would require keeping a reference to
the frame in which an annotation got created. This could be achieved
for example by storing all annotations as lambdas instead of strings.</p>
<p>This would be prohibitively expensive for highly annotated code as the
frames would keep all their objects alive. That includes predominantly
objects that wont ever be accessed again.</p>
<p>To be able to address class-level scope, the lambda approach would
require a new kind of cell in the interpreter. This would proliferate
the number of types that can appear in <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code>, as well as
wouldnt be as introspectable as strings.</p>
<p>Note that in the case of nested classes, the functionality to get the
effective “globals” and “locals” at definition time is provided by
<code class="docutils literal notranslate"><span class="pre">typing.get_type_hints()</span></code>.</p>
<p>If a function generates a class or a function with annotations that
have to use local variables, it can populate the given generated
objects <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> dictionary directly, without relying on
the compiler.</p>
</section>
<section id="disallowing-local-state-usage-for-classes-too">
<h3><a class="toc-backref" href="#disallowing-local-state-usage-for-classes-too" role="doc-backlink">Disallowing local state usage for classes, too</a></h3>
<p>This PEP originally proposed limiting names within annotations to only
allow names from the model-level scope, including for classes. The
author argued this makes name resolution unambiguous, including in cases
of conflicts between local names and module-level names.</p>
<p>This idea was ultimately rejected in case of classes. Instead,
<code class="docutils literal notranslate"><span class="pre">typing.get_type_hints()</span></code> got modified to populate the local namespace
correctly if class-level annotations are needed.</p>
<p>The reasons for rejecting the idea were that it goes against the
intuition of how scoping works in Python, and would break enough
existing type annotations to make the transition cumbersome. Finally,
local scope access is required for class decorators to be able to
evaluate type annotations. This is because class decorators are applied
before the class receives its name in the outer scope.</p>
</section>
<section id="introducing-a-new-dictionary-for-the-string-literal-form-instead">
<h3><a class="toc-backref" href="#introducing-a-new-dictionary-for-the-string-literal-form-instead" role="doc-backlink">Introducing a new dictionary for the string literal form instead</a></h3>
<p>Yury Selivanov shared the following idea:</p>
<ol class="arabic simple">
<li>Add a new special attribute to functions: <code class="docutils literal notranslate"><span class="pre">__annotations_text__</span></code>.</li>
<li>Make <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> a lazy dynamic mapping, evaluating
expressions from the corresponding key in <code class="docutils literal notranslate"><span class="pre">__annotations_text__</span></code>
just-in-time.</li>
</ol>
<p>This idea is supposed to solve the backwards compatibility issue,
removing the need for a new <code class="docutils literal notranslate"><span class="pre">__future__</span></code> import. Sadly, this is not
enough. Postponed evaluation changes which state the annotation has
access to. While postponed evaluation fixes the forward reference
problem, it also makes it impossible to access function-level locals
anymore. This alone is a source of backwards incompatibility which
justifies a deprecation period.</p>
<p>A <code class="docutils literal notranslate"><span class="pre">__future__</span></code> import is an obvious and explicit indicator of opting
in for the new functionality. It also makes it trivial for external
tools to recognize the difference between a Python files using the old
or the new approach. In the former case, that tool would recognize that
local state access is allowed, whereas in the latter case it would
recognize that forward references are allowed.</p>
<p>Finally, just-in-time evaluation in <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> is an
unnecessary step if <code class="docutils literal notranslate"><span class="pre">get_type_hints()</span></code> is used later.</p>
</section>
<section id="dropping-annotations-with-o">
<h3><a class="toc-backref" href="#dropping-annotations-with-o" role="doc-backlink">Dropping annotations with -O</a></h3>
<p>There are two reasons this is not satisfying for the purpose of this
PEP.</p>
<p>First, this only addresses runtime cost, not forward references, those
still cannot be safely used in source code. A library maintainer would
never be able to use forward references since that would force the
library users to use this new hypothetical -O switch.</p>
<p>Second, this throws the baby out with the bath water. Now <em>no</em> runtime
annotation use can be performed. <a class="pep reference internal" href="../pep-0557/" title="PEP 557 Data Classes">PEP 557</a> is one example of a recent
development where evaluating type annotations at runtime is useful.</p>
<p>All that being said, a granular -O option to drop annotations is
a possibility in the future, as its conceptually compatible with
existing -O behavior (dropping docstrings and assert statements). This
PEP does not invalidate the idea.</p>
</section>
<section id="passing-string-literals-in-annotations-verbatim-to-annotations">
<h3><a class="toc-backref" href="#passing-string-literals-in-annotations-verbatim-to-annotations" role="doc-backlink">Passing string literals in annotations verbatim to <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code></a></h3>
<p>This PEP originally suggested directly storing the contents of a string
literal under its respective key in <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code>. This was
meant to simplify support for runtime type checkers.</p>
<p>Mark Shannon pointed out this idea was flawed since it wasnt handling
situations where strings are only part of a type annotation.</p>
<p>The inconsistency of it was always apparent but given that it doesnt
fully prevent cases of double-wrapping strings anyway, it is not worth
it.</p>
</section>
<section id="making-the-name-of-the-future-import-more-verbose">
<h3><a class="toc-backref" href="#making-the-name-of-the-future-import-more-verbose" role="doc-backlink">Making the name of the future import more verbose</a></h3>
<p>Instead of requiring the following import:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">annotations</span>
</pre></div>
</div>
<p>the PEP could call the feature more explicitly, for example
<code class="docutils literal notranslate"><span class="pre">string_annotations</span></code>, <code class="docutils literal notranslate"><span class="pre">stringify_annotations</span></code>,
<code class="docutils literal notranslate"><span class="pre">annotation_strings</span></code>, <code class="docutils literal notranslate"><span class="pre">annotations_as_strings</span></code>, <code class="docutils literal notranslate"><span class="pre">lazy_annotations</span></code>,
<code class="docutils literal notranslate"><span class="pre">static_annotations</span></code>, etc.</p>
<p>The problem with those names is that they are very verbose. Each of
them besides <code class="docutils literal notranslate"><span class="pre">lazy_annotations</span></code> would constitute the longest future
feature name in Python. They are long to type and harder to remember
than the single-word form.</p>
<p>There is precedence of a future import name that sounds overly generic
but in practice was obvious to users as to what it does:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">division</span>
</pre></div>
</div>
</section>
</section>
<section id="prior-discussion">
<h2><a class="toc-backref" href="#prior-discussion" role="doc-backlink">Prior discussion</a></h2>
<section id="in-pep-484">
<h3><a class="toc-backref" href="#in-pep-484" role="doc-backlink">In PEP 484</a></h3>
<p>The forward reference problem was discussed when <a class="pep reference internal" href="../pep-0484/" title="PEP 484 Type Hints">PEP 484</a> was originally
drafted, leading to the following statement in the document:</p>
<blockquote>
<div>A compromise is possible where a <code class="docutils literal notranslate"><span class="pre">__future__</span></code> import could enable
turning <em>all</em> annotations in a given module into string literals, as
follows:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">annotations</span>
<span class="k">class</span> <span class="nc">ImSet</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">add</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">a</span><span class="p">:</span> <span class="n">ImSet</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">ImSet</span><span class="p">]:</span> <span class="o">...</span>
<span class="k">assert</span> <span class="n">ImSet</span><span class="o">.</span><span class="n">add</span><span class="o">.</span><span class="vm">__annotations__</span> <span class="o">==</span> <span class="p">{</span>
<span class="s1">&#39;a&#39;</span><span class="p">:</span> <span class="s1">&#39;ImSet&#39;</span><span class="p">,</span> <span class="s1">&#39;return&#39;</span><span class="p">:</span> <span class="s1">&#39;List[ImSet]&#39;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Such a <code class="docutils literal notranslate"><span class="pre">__future__</span></code> import statement may be proposed in a separate
PEP.</p>
</div></blockquote>
</section>
<section id="python-typing-400">
<h3><a class="toc-backref" href="#python-typing-400" role="doc-backlink">python/typing#400</a></h3>
<p>The problem was discussed at length on the typing modules GitHub
project, under <a class="reference external" href="https://github.com/python/typing/issues/400">Issue 400</a>.
The problem statement there includes critique of generic types requiring
imports from <code class="docutils literal notranslate"><span class="pre">typing</span></code>. This tends to be confusing to
beginners:</p>
<blockquote>
<div>Why this:<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">List</span><span class="p">,</span> <span class="n">Set</span>
<span class="k">def</span> <span class="nf">dir</span><span class="p">(</span><span class="n">o</span><span class="p">:</span> <span class="nb">object</span> <span class="o">=</span> <span class="o">...</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span> <span class="o">...</span>
<span class="k">def</span> <span class="nf">add_friends</span><span class="p">(</span><span class="n">friends</span><span class="p">:</span> <span class="n">Set</span><span class="p">[</span><span class="n">Friend</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span> <span class="o">...</span>
</pre></div>
</div>
<p>But not this:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">dir</span><span class="p">(</span><span class="n">o</span><span class="p">:</span> <span class="nb">object</span> <span class="o">=</span> <span class="o">...</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span> <span class="o">...</span>
<span class="k">def</span> <span class="nf">add_friends</span><span class="p">(</span><span class="n">friends</span><span class="p">:</span> <span class="nb">set</span><span class="p">[</span><span class="n">Friend</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="kc">None</span> <span class="o">...</span>
</pre></div>
</div>
<p>Why this:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">up_to_ten</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">))</span>
<span class="n">friends</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
</pre></div>
</div>
<p>But not this:</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">List</span><span class="p">,</span> <span class="n">Set</span>
<span class="n">up_to_ten</span> <span class="o">=</span> <span class="n">List</span><span class="p">[</span><span class="nb">int</span><span class="p">](</span><span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">))</span>
<span class="n">friends</span> <span class="o">=</span> <span class="n">Set</span><span class="p">[</span><span class="n">Friend</span><span class="p">]()</span>
</pre></div>
</div>
</div></blockquote>
<p>While typing usability is an interesting problem, it is out of scope
of this PEP. Specifically, any extensions of the typing syntax
standardized in <a class="pep reference internal" href="../pep-0484/" title="PEP 484 Type Hints">PEP 484</a> will require their own respective PEPs and
approval.</p>
<p>Issue 400 ultimately suggests postponing evaluation of annotations and
keeping them as strings in <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code>, just like this PEP
specifies. This idea was received well. Ivan Levkivskyi supported
using the <code class="docutils literal notranslate"><span class="pre">__future__</span></code> import and suggested unparsing the AST in
<code class="docutils literal notranslate"><span class="pre">compile.c</span></code>. Jukka Lehtosalo pointed out that there are some cases
of forward references where types are used outside of annotations and
postponed evaluation will not help those. For those cases using the
string literal notation would still be required. Those cases are
discussed briefly in the “Forward References” section of this PEP.</p>
<p>The biggest controversy on the issue was Guido van Rossums concern
that untokenizing annotation expressions back to their string form has
no precedent in the Python programming language and feels like a hacky
workaround. He said:</p>
<blockquote>
<div>One thing that comes to mind is that its a very random change to
the language. It might be useful to have a more compact way to
indicate deferred execution of expressions (using less syntax than
<code class="docutils literal notranslate"><span class="pre">lambda:</span></code>). But why would the use case of type annotations be so
all-important to change the language to do it there first (rather
than proposing a more general solution), given that theres already
a solution for this particular use case that requires very minimal
syntax?</div></blockquote>
<p>Eventually, Ethan Smith and schollii voiced that feedback gathered
during PyCon US suggests that the state of forward references needs
fixing. Guido van Rossum suggested coming back to the <code class="docutils literal notranslate"><span class="pre">__future__</span></code>
idea, pointing out that to prevent abuse, its important for the
annotations to be kept both syntactically valid and evaluating correctly
at runtime.</p>
</section>
<section id="first-draft-discussion-on-python-ideas">
<h3><a class="toc-backref" href="#first-draft-discussion-on-python-ideas" role="doc-backlink">First draft discussion on python-ideas</a></h3>
<p>Discussion happened largely in two threads, <a class="reference external" href="https://mail.python.org/pipermail/python-ideas/2017-September/thread.html#47031">the original announcement</a>
and a follow-up called <a class="reference external" href="https://mail.python.org/pipermail/python-ideas/2017-September/thread.html#47108">PEP 563 and expensive backwards compatibility</a>.</p>
<p>The PEP received rather warm feedback (4 strongly in favor,
2 in favor with concerns, 2 against). The biggest voice of concern on
the former thread being Steven DApranos review stating that the
problem definition of the PEP doesnt justify breaking backwards
compatibility. In this response Steven seemed mostly concerned about
Python no longer supporting evaluation of annotations that depended on
local function/class state.</p>
<p>A few people voiced concerns that there are libraries using annotations
for non-typing purposes. However, none of the named libraries would be
invalidated by this PEP. They do require adapting to the new
requirement to call <code class="docutils literal notranslate"><span class="pre">eval()</span></code> on the annotation with the correct
<code class="docutils literal notranslate"><span class="pre">globals</span></code> and <code class="docutils literal notranslate"><span class="pre">locals</span></code> set.</p>
<p>This detail about <code class="docutils literal notranslate"><span class="pre">globals</span></code> and <code class="docutils literal notranslate"><span class="pre">locals</span></code> having to be correct was
picked up by a number of commenters. Alyssa (Nick) Coghlan benchmarked turning
annotations into lambdas instead of strings, sadly this proved to be
much slower at runtime than the current situation.</p>
<p>The latter thread was started by Jim J. Jewett who stressed that
the ability to properly evaluate annotations is an important requirement
and backwards compatibility in that regard is valuable. After some
discussion he admitted that side effects in annotations are a code smell
and modal support to either perform or not perform evaluation is
a messy solution. His biggest concern remained loss of functionality
stemming from the evaluation restrictions on global and local scope.</p>
<p>Alyssa Coghlan pointed out that some of those evaluation restrictions from
the PEP could be lifted by a clever implementation of an evaluation
helper, which could solve self-referencing classes even in the form of a
class decorator. She suggested the PEP should provide this helper
function in the standard library.</p>
</section>
<section id="second-draft-discussion-on-python-dev">
<h3><a class="toc-backref" href="#second-draft-discussion-on-python-dev" role="doc-backlink">Second draft discussion on python-dev</a></h3>
<p>Discussion happened mainly in the <a class="reference external" href="https://mail.python.org/pipermail/python-dev/2017-November/150062.html">announcement thread</a>,
followed by a brief discussion under <a class="reference external" href="https://mail.python.org/pipermail/python-dev/2017-November/150637.html">Mark Shannons post</a>.</p>
<p>Steven DAprano was concerned whether its acceptable for typos to be
allowed in annotations after the change proposed by the PEP. Brett
Cannon responded that type checkers and other static analyzers (like
linters or programming text editors) will catch this type of error.
Jukka Lehtosalo added that this situation is analogous to how names in
function bodies are not resolved until the function is called.</p>
<p>A major topic of discussion was Alyssa Coghlans suggestion to store
annotations in “thunk form”, in other words as a specialized lambda
which would be able to access class-level scope (and allow for scope
customization at call time). He presented a possible design for it
(<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2017-November/150141.html">indirect attribute cells</a>).
This was later seen as equivalent to “special forms” in Lisp. Guido van
Rossum expressed worry that this sort of feature cannot be safely
implemented in twelve weeks (i.e. in time before the Python 3.7 beta
freeze).</p>
<p>After a while it became clear that the point of division between
supporters of the string form vs. supporters of the thunk form is
actually about whether annotations should be perceived as a general
syntactic element vs. something tied to the type checking use case.</p>
<p>Finally, Guido van Rossum declared hes rejecting the thunk idea
based on the fact that it would require a new building block in the
interpreter. This block would be exposed in annotations, multiplying
possible types of values stored in <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> (arbitrary
objects, strings, and now thunks). Moreover, thunks arent as
introspectable as strings. Most importantly, Guido van Rossum
explicitly stated interest in gradually restricting the use of
annotations to static typing (with an optional runtime component).</p>
<p>Alyssa Coghlan got convinced to <a class="pep reference internal" href="../pep-0563/" title="PEP 563 Postponed Evaluation of Annotations">PEP 563</a>, too, promptly beginning
the mandatory bike shedding session on the name of the <code class="docutils literal notranslate"><span class="pre">__future__</span></code>
import. Many debaters agreed that <code class="docutils literal notranslate"><span class="pre">annotations</span></code> seems like
an overly broad name for the feature name. Guido van Rossum briefly
decided to call it <code class="docutils literal notranslate"><span class="pre">string_annotations</span></code> but then changed his mind,
arguing that <code class="docutils literal notranslate"><span class="pre">division</span></code> is a precedent of a broad name with a clear
meaning.</p>
<p>The final improvement to the PEP suggested in the discussion by Mark
Shannon was the rejection of the temptation to pass string literals
through to <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code> verbatim.</p>
<p>A side-thread of discussion started around the runtime penalty of
static typing, with topic like the import time of the <code class="docutils literal notranslate"><span class="pre">typing</span></code>
module (which is comparable to <code class="docutils literal notranslate"><span class="pre">re</span></code> without dependencies, and
three times as heavy as <code class="docutils literal notranslate"><span class="pre">re</span></code> when counting dependencies).</p>
</section>
</section>
<section id="acknowledgements">
<h2><a class="toc-backref" href="#acknowledgements" role="doc-backlink">Acknowledgements</a></h2>
<p>This document could not be completed without valuable input,
encouragement and advice from Guido van Rossum, Jukka Lehtosalo, and
Ivan Levkivskyi.</p>
<p>The implementation was thoroughly reviewed by Serhiy Storchaka who
found all sorts of issues, including bugs, bad readability, and
performance problems.</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-0563.rst">https://github.com/python/peps/blob/main/peps/pep-0563.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0563.rst">2024-03-24 01:43:58 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="#rationale-and-goals">Rationale and Goals</a><ul>
<li><a class="reference internal" href="#non-goals">Non-goals</a></li>
<li><a class="reference internal" href="#non-typing-usage-of-annotations">Non-typing usage of annotations</a></li>
</ul>
</li>
<li><a class="reference internal" href="#implementation">Implementation</a><ul>
<li><a class="reference internal" href="#enabling-the-future-behavior-in-python-3-7">Enabling the future behavior in Python 3.7</a></li>
</ul>
</li>
<li><a class="reference internal" href="#resolving-type-hints-at-runtime">Resolving Type Hints at Runtime</a><ul>
<li><a class="reference internal" href="#runtime-annotation-resolution-and-class-decorators">Runtime annotation resolution and class decorators</a></li>
<li><a class="reference internal" href="#runtime-annotation-resolution-and-type-checking">Runtime annotation resolution and <code class="docutils literal notranslate"><span class="pre">TYPE_CHECKING</span></code></a></li>
</ul>
</li>
<li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a><ul>
<li><a class="reference internal" href="#deprecation-policy">Deprecation policy</a></li>
</ul>
</li>
<li><a class="reference internal" href="#forward-references">Forward References</a></li>
<li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul>
<li><a class="reference internal" href="#keeping-the-ability-to-use-function-local-state-when-defining-annotations">Keeping the ability to use function local state when defining annotations</a></li>
<li><a class="reference internal" href="#disallowing-local-state-usage-for-classes-too">Disallowing local state usage for classes, too</a></li>
<li><a class="reference internal" href="#introducing-a-new-dictionary-for-the-string-literal-form-instead">Introducing a new dictionary for the string literal form instead</a></li>
<li><a class="reference internal" href="#dropping-annotations-with-o">Dropping annotations with -O</a></li>
<li><a class="reference internal" href="#passing-string-literals-in-annotations-verbatim-to-annotations">Passing string literals in annotations verbatim to <code class="docutils literal notranslate"><span class="pre">__annotations__</span></code></a></li>
<li><a class="reference internal" href="#making-the-name-of-the-future-import-more-verbose">Making the name of the future import more verbose</a></li>
</ul>
</li>
<li><a class="reference internal" href="#prior-discussion">Prior discussion</a><ul>
<li><a class="reference internal" href="#in-pep-484">In PEP 484</a></li>
<li><a class="reference internal" href="#python-typing-400">python/typing#400</a></li>
<li><a class="reference internal" href="#first-draft-discussion-on-python-ideas">First draft discussion on python-ideas</a></li>
<li><a class="reference internal" href="#second-draft-discussion-on-python-dev">Second draft discussion on python-dev</a></li>
</ul>
</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-0563.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>