719 lines
78 KiB
HTML
719 lines
78 KiB
HTML
|
||
<!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 747 – Annotating Type Forms | peps.python.org</title>
|
||
<link rel="shortcut icon" href="../_static/py.png">
|
||
<link rel="canonical" href="https://peps.python.org/pep-0747/">
|
||
<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 747 – Annotating Type Forms | peps.python.org'>
|
||
<meta property="og:description" content="Type expressions provide a standardized way to specify types in the Python type system. When a type expression is evaluated at runtime, the resulting type form object encodes the information supplied in the type expression. This enables a variety of use...">
|
||
<meta property="og:type" content="website">
|
||
<meta property="og:url" content="https://peps.python.org/pep-0747/">
|
||
<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="Type expressions provide a standardized way to specify types in the Python type system. When a type expression is evaluated at runtime, the resulting type form object encodes the information supplied in the type expression. This enables a variety of use...">
|
||
<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 747</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 747 – Annotating Type Forms</h1>
|
||
<dl class="rfc2822 field-list simple">
|
||
<dt class="field-odd">Author<span class="colon">:</span></dt>
|
||
<dd class="field-odd">David Foster <david at dafoster.net>, Eric Traut <erictr at microsoft.com></dd>
|
||
<dt class="field-even">Sponsor<span class="colon">:</span></dt>
|
||
<dd class="field-even">Jelle Zijlstra <jelle.zijlstra at gmail.com></dd>
|
||
<dt class="field-odd">Discussions-To<span class="colon">:</span></dt>
|
||
<dd class="field-odd"><a class="reference external" href="https://discuss.python.org/t/pep-747-typeexpr-type-hint-for-a-type-expression/55984">Discourse thread</a></dd>
|
||
<dt class="field-even">Status<span class="colon">:</span></dt>
|
||
<dd class="field-even"><abbr title="Proposal under active discussion and revision">Draft</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">27-May-2024</dd>
|
||
<dt class="field-even">Python-Version<span class="colon">:</span></dt>
|
||
<dd class="field-even">3.14</dd>
|
||
<dt class="field-odd">Post-History<span class="colon">:</span></dt>
|
||
<dd class="field-odd"><a class="reference external" href="https://discuss.python.org/t/typeform-spelling-for-a-type-annotation-object-at-runtime/51435" title="Discourse thread">19-Apr-2024</a>, <a class="reference external" href="https://discuss.python.org/t/typeform-spelling-for-a-type-annotation-object-at-runtime/51435/7/" title="Discourse message">04-May-2024</a>, <a class="reference external" href="https://discuss.python.org/t/pep-747-typeexpr-type-hint-for-a-type-expression/55984" title="Discourse thread">17-Jun-2024</a></dd>
|
||
</dl>
|
||
<hr class="docutils" />
|
||
<section id="contents">
|
||
<details><summary>Table of Contents</summary><ul class="simple">
|
||
<li><a class="reference internal" href="#abstract">Abstract</a></li>
|
||
<li><a class="reference internal" href="#motivation">Motivation</a><ul>
|
||
<li><a class="reference internal" href="#why-not-type-c">Why not <code class="docutils literal notranslate"><span class="pre">type[C]</span></code>?</a></li>
|
||
<li><a class="reference internal" href="#typeform-use-cases">TypeForm use cases</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#specification">Specification</a><ul>
|
||
<li><a class="reference internal" href="#implicit-typeform-evaluation">Implicit <code class="docutils literal notranslate"><span class="pre">TypeForm</span></code> Evaluation</a></li>
|
||
<li><a class="reference internal" href="#explicit-typeform-evaluation">Explicit <code class="docutils literal notranslate"><span class="pre">TypeForm</span></code> Evaluation</a></li>
|
||
<li><a class="reference internal" href="#assignability">Assignability</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#backward-compatibility">Backward Compatibility</a></li>
|
||
<li><a class="reference internal" href="#how-to-teach-this">How to Teach This</a></li>
|
||
<li><a class="reference internal" href="#advanced-examples">Advanced Examples</a><ul>
|
||
<li><a class="reference internal" href="#introspecting-type-form-objects">Introspecting type form objects</a></li>
|
||
<li><a class="reference internal" href="#combining-with-a-type-variable">Combining with a type variable</a></li>
|
||
<li><a class="reference internal" href="#combining-with-type">Combining with <code class="docutils literal notranslate"><span class="pre">type</span></code></a></li>
|
||
<li><a class="reference internal" href="#combining-with-typeis-and-typeguard">Combining with <code class="docutils literal notranslate"><span class="pre">TypeIs</span></code> and <code class="docutils literal notranslate"><span class="pre">TypeGuard</span></code></a></li>
|
||
<li><a class="reference internal" href="#challenges-when-accepting-all-typeforms">Challenges When Accepting All TypeForms</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li>
|
||
<li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul>
|
||
<li><a class="reference internal" href="#alternative-names">Alternative names</a></li>
|
||
<li><a class="reference internal" href="#widen-type-c-to-support-all-type-expressions">Widen <code class="docutils literal notranslate"><span class="pre">type[C]</span></code> to support all type expressions</a></li>
|
||
<li><a class="reference internal" href="#accept-arbitrary-annotation-expressions">Accept arbitrary annotation expressions</a></li>
|
||
<li><a class="reference internal" href="#pattern-matching-on-type-forms">Pattern matching on type forms</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#footnotes">Footnotes</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="reference external" href="https://typing.readthedocs.io/en/latest/spec/annotations.html#type-expression" title="(in typing)"><span class="xref std std-ref">Type expressions</span></a> provide a standardized way
|
||
to specify types in the Python type system. When a type expression is
|
||
evaluated at runtime, the resulting <em>type form object</em> encodes the information
|
||
supplied in the type expression. This enables a variety of use cases including
|
||
runtime type checking, introspection, and metaprogramming.</p>
|
||
<p>Such use cases have proliferated, but there is currently no way to accurately
|
||
annotate functions that accept type form objects. Developers are forced to use
|
||
an overly-wide type like <code class="docutils literal notranslate"><span class="pre">object</span></code>, which makes some use cases impossible and
|
||
generally reduces type safety. This PEP addresses this limitation by
|
||
introducing a new special form <code class="docutils literal notranslate"><span class="pre">typing.TypeForm</span></code>.</p>
|
||
<p>This PEP makes no changes to the Python grammar. Correct usage of <code class="docutils literal notranslate"><span class="pre">TypeForm</span></code> is
|
||
intended to be enforced only by type checkers, not by the Python runtime.</p>
|
||
</section>
|
||
<section id="motivation">
|
||
<h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2>
|
||
<p>A function that operates on type form objects must understand how type
|
||
expression details are encoded in these objects. For example, <code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">|</span> <span class="pre">str</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">"int</span> <span class="pre">|</span> <span class="pre">str"</span></code>, <code class="docutils literal notranslate"><span class="pre">list[int]</span></code>, and <code class="docutils literal notranslate"><span class="pre">MyTypeAlias</span></code> are all valid type
|
||
expressions, and they evaluate to instances of <code class="docutils literal notranslate"><span class="pre">types.UnionType</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">builtins.str</span></code>, <code class="docutils literal notranslate"><span class="pre">types.GenericAlias</span></code>, and <code class="docutils literal notranslate"><span class="pre">typing.TypeAliasType</span></code>,
|
||
respectively.</p>
|
||
<p>There is currently no way to indicate to a type checker that a function accepts
|
||
type form objects and knows how to work with them. <code class="docutils literal notranslate"><span class="pre">TypeForm</span></code> addresses this
|
||
limitation. For example, here is a function that checks whether a value is
|
||
assignable to a specified type and returns None if it is not:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">trycast</span><span class="p">[</span><span class="n">T</span><span class="p">](</span><span class="n">typx</span><span class="p">:</span> <span class="n">TypeForm</span><span class="p">[</span><span class="n">T</span><span class="p">],</span> <span class="n">value</span><span class="p">:</span> <span class="nb">object</span><span class="p">)</span> <span class="o">-></span> <span class="n">T</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span> <span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The use of <code class="docutils literal notranslate"><span class="pre">TypeForm</span></code> and the type variable <code class="docutils literal notranslate"><span class="pre">T</span></code> describes a relationship
|
||
between the type form passed to parameter <code class="docutils literal notranslate"><span class="pre">typx</span></code> and the function’s
|
||
return type.</p>
|
||
<p><code class="docutils literal notranslate"><span class="pre">TypeForm</span></code> can also be used with <a class="reference external" href="https://typing.readthedocs.io/en/latest/spec/narrowing.html#typeis" title="(in typing)"><span>TypeIs</span></a> to define custom type
|
||
narrowing behaviors:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">isassignable</span><span class="p">[</span><span class="n">T</span><span class="p">](</span><span class="n">value</span><span class="p">:</span> <span class="nb">object</span><span class="p">,</span> <span class="n">typx</span><span class="p">:</span> <span class="n">TypeForm</span><span class="p">[</span><span class="n">T</span><span class="p">])</span> <span class="o">-></span> <span class="n">TypeIs</span><span class="p">[</span><span class="n">T</span><span class="p">]:</span> <span class="o">...</span>
|
||
|
||
<span class="n">request_json</span><span class="p">:</span> <span class="nb">object</span> <span class="o">=</span> <span class="o">...</span>
|
||
<span class="k">if</span> <span class="n">isassignable</span><span class="p">(</span><span class="n">request_json</span><span class="p">,</span> <span class="n">MyTypedDict</span><span class="p">):</span>
|
||
<span class="n">assert_type</span><span class="p">(</span><span class="n">request_json</span><span class="p">,</span> <span class="n">MyTypedDict</span><span class="p">)</span> <span class="c1"># Type of variable is narrowed</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">isassignable</span></code> function implements something like an enhanced
|
||
<code class="docutils literal notranslate"><span class="pre">isinstance</span></code> check. This is useful for validating whether a value decoded
|
||
from JSON conforms to a particular structure of nested <code class="docutils literal notranslate"><span class="pre">TypedDict</span></code>s,
|
||
lists, unions, <code class="docutils literal notranslate"><span class="pre">Literal</span></code>s, or any other type form that can be described
|
||
with a type expression. This kind of check was alluded to in
|
||
<a class="pep reference internal" href="../pep-0589/#using-typeddict-types" title="PEP 589 – TypedDict: Type Hints for Dictionaries with a Fixed Set of Keys § Using TypedDict Types">PEP 589</a> but could not be implemented without
|
||
<code class="docutils literal notranslate"><span class="pre">TypeForm</span></code>.</p>
|
||
<section id="why-not-type-c">
|
||
<h3><a class="toc-backref" href="#why-not-type-c" role="doc-backlink">Why not <code class="docutils literal notranslate"><span class="pre">type[C]</span></code>?</a></h3>
|
||
<p>One might think that <code class="docutils literal notranslate"><span class="pre">type[C]</span></code> would suffice for these use cases. However,
|
||
only class objects (instances of the <code class="docutils literal notranslate"><span class="pre">builtins.type</span></code> class) are assignable
|
||
to <code class="docutils literal notranslate"><span class="pre">type[C]</span></code>. Many type form objects do not meet this requirement:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">trycast</span><span class="p">[</span><span class="n">T</span><span class="p">](</span><span class="n">typx</span><span class="p">:</span> <span class="nb">type</span><span class="p">[</span><span class="n">T</span><span class="p">],</span> <span class="n">value</span><span class="p">:</span> <span class="nb">object</span><span class="p">)</span> <span class="o">-></span> <span class="n">T</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span> <span class="o">...</span>
|
||
|
||
<span class="n">trycast</span><span class="p">(</span><span class="nb">str</span><span class="p">,</span> <span class="s1">'hi'</span><span class="p">)</span> <span class="c1"># OK</span>
|
||
<span class="n">trycast</span><span class="p">(</span><span class="n">Literal</span><span class="p">[</span><span class="s1">'hi'</span><span class="p">],</span> <span class="s1">'hi'</span><span class="p">)</span> <span class="c1"># Type violation</span>
|
||
<span class="n">trycast</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="s1">'hi'</span><span class="p">)</span> <span class="c1"># Type violation</span>
|
||
<span class="n">trycast</span><span class="p">(</span><span class="n">MyProtocolClass</span><span class="p">,</span> <span class="n">obj</span><span class="p">)</span> <span class="c1"># Type violation</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="typeform-use-cases">
|
||
<h3><a class="toc-backref" href="#typeform-use-cases" role="doc-backlink">TypeForm use cases</a></h3>
|
||
<p><a class="reference external" href="https://github.com/python/mypy/issues/9773#issuecomment-2017998886">A survey of Python libraries</a> reveals several categories of functions that
|
||
would benefit from <code class="docutils literal notranslate"><span class="pre">TypeForm</span></code>:</p>
|
||
<ul class="simple">
|
||
<li>Assignability checkers:<ul>
|
||
<li>Determines whether a value is assignable to a specified type</li>
|
||
<li>Pattern 1: <code class="docutils literal notranslate"><span class="pre">def</span> <span class="pre">is_assignable[T](value:</span> <span class="pre">object,</span> <span class="pre">typx:</span> <span class="pre">TypeForm[T])</span> <span class="pre">-></span> <span class="pre">TypeIs[T]</span></code></li>
|
||
<li>Pattern 2: <code class="docutils literal notranslate"><span class="pre">def</span> <span class="pre">is_match[T](value:</span> <span class="pre">object,</span> <span class="pre">typx:</span> <span class="pre">TypeForm[T])</span> <span class="pre">-></span> <span class="pre">TypeGuard[T]</span></code></li>
|
||
<li>Examples: beartype.<a class="reference external" href="https://github.com/beartype/beartype/issues/255">is_bearable</a>, trycast.<a class="reference external" href="https://github.com/davidfstr/trycast?tab=readme-ov-file#isassignable-api">isassignable</a>,
|
||
typeguard.<a class="reference external" href="https://typeguard.readthedocs.io/en/latest/api.html#typeguard.check_type">check_type</a>, xdsl.<a class="reference external" href="https://github.com/xdslproject/xdsl/blob/ac12c9ab0d64618475efb98d1d197bdd79f593c3/xdsl/utils/hints.py#L23">isa</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>Converters:<ul>
|
||
<li>If a value is assignable to (or coercible to) a specified type,
|
||
a <em>converter</em> returns the value narrowed to (or coerced to) that type.
|
||
Otherwise, an exception is raised.</li>
|
||
<li>Pattern 1:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">convert</span><span class="p">[</span><span class="n">T</span><span class="p">](</span><span class="n">value</span><span class="p">:</span> <span class="nb">object</span><span class="p">,</span> <span class="n">typx</span><span class="p">:</span> <span class="n">TypeForm</span><span class="p">[</span><span class="n">T</span><span class="p">])</span> <span class="o">-></span> <span class="n">T</span>
|
||
</pre></div>
|
||
</div>
|
||
<ul class="simple">
|
||
<li>Examples: cattrs.BaseConverter.<a class="reference external" href="https://github.com/python-attrs/cattrs/blob/5f5c11627a7f67a23d6212bc7df9f96243c62dc5/src/cattrs/converters.py#L332-L334">structure</a>, trycast.<a class="reference external" href="https://github.com/davidfstr/trycast#checkcast-api">checkcast</a>,
|
||
typedload.<a class="reference external" href="https://ltworf.github.io/typedload/">load</a></li>
|
||
</ul>
|
||
</li>
|
||
<li>Pattern 2:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Converter</span><span class="p">[</span><span class="n">T</span><span class="p">]:</span>
|
||
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">typx</span><span class="p">:</span> <span class="n">TypeForm</span><span class="p">[</span><span class="n">T</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">def</span> <span class="nf">convert</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">object</span><span class="p">)</span> <span class="o">-></span> <span class="n">T</span><span class="p">:</span> <span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
<ul class="simple">
|
||
<li>Examples: pydantic.<a class="reference external" href="https://stackoverflow.com/a/61021183/604063">TypeAdapter(T).validate_python</a>,
|
||
mashumaro.<a class="reference external" href="https://github.com/Fatal1ty/mashumaro?tab=readme-ov-file#usage-example">JSONDecoder(T).decode</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
<ul>
|
||
<li>Typed field definitions:<ul>
|
||
<li>Pattern:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Field</span><span class="p">[</span><span class="n">T</span><span class="p">]:</span>
|
||
<span class="n">value_type</span><span class="p">:</span> <span class="n">TypeForm</span><span class="p">[</span><span class="n">T</span><span class="p">]</span>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
<li>Examples: attrs.<a class="reference external" href="https://www.attrs.org/en/stable/api.html#attrs.make_class">make_class</a>,
|
||
dataclasses.<a class="reference external" href="https://github.com/python/typeshed/issues/11653">make_dataclass</a> <a class="footnote-reference brackets" href="#dataclassinitvar" id="id1">[3]</a>, <a class="reference external" href="https://github.com/Fatal1ty/openapify/blob/c8d968c7c9c8fd7d4888bd2ddbe18ffd1469f3ca/openapify/core/models.py#L16">openapify</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
<p>The survey also identified some introspection functions that accept runtime
|
||
type forms as input. Today, these functions are annotated with <code class="docutils literal notranslate"><span class="pre">object</span></code>:</p>
|
||
<ul class="simple">
|
||
<li>General introspection operations:<ul>
|
||
<li>Pattern: <code class="docutils literal notranslate"><span class="pre">def</span> <span class="pre">get_annotation_info(typx:</span> <span class="pre">object)</span> <span class="pre">-></span> <span class="pre">object</span></code></li>
|
||
<li>Examples: typing.{<a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.get_origin">get_origin</a>, <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.get_args">get_args</a>},
|
||
<a class="reference external" href="https://github.com/ilevkivskyi/typing_inspect?tab=readme-ov-file#readme">typing_inspect</a>.{is_*_type, get_origin, get_parameters}</li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
<p>These functions accept values evaluated from arbitrary annotation expressions,
|
||
not just type expressions, so they cannot be altered to use <code class="docutils literal notranslate"><span class="pre">TypeForm</span></code>.</p>
|
||
</section>
|
||
</section>
|
||
<section id="specification">
|
||
<h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2>
|
||
<p>When a type expression is evaluated at runtime, the resulting value is a
|
||
<em>type form</em> object. This value encodes the information supplied in the type
|
||
expression, and it represents the type described by that type expression.</p>
|
||
<p><code class="docutils literal notranslate"><span class="pre">TypeForm</span></code> is a special form that, when used in a type expression, describes
|
||
a set of type form objects. It accepts a single type argument, which must be a
|
||
valid type expression. <code class="docutils literal notranslate"><span class="pre">TypeForm[T]</span></code> describes the set of all type form
|
||
objects that represent the type <code class="docutils literal notranslate"><span class="pre">T</span></code> or types that are
|
||
<a class="reference external" href="https://typing.readthedocs.io/en/latest/spec/glossary.html#term-assignable" title="(in typing)"><span class="xref std std-term">assignable to</span></a> <code class="docutils literal notranslate"><span class="pre">T</span></code>. For example,
|
||
<code class="docutils literal notranslate"><span class="pre">TypeForm[str</span> <span class="pre">|</span> <span class="pre">None]</span></code> describes the set of all type form objects
|
||
that represent a type assignable to <code class="docutils literal notranslate"><span class="pre">str</span> <span class="pre">|</span> <span class="pre">None</span></code>:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">ok1</span><span class="p">:</span> <span class="n">TypeForm</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="o">=</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="c1"># OK</span>
|
||
<span class="n">ok2</span><span class="p">:</span> <span class="n">TypeForm</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="o">=</span> <span class="nb">str</span> <span class="c1"># OK</span>
|
||
<span class="n">ok3</span><span class="p">:</span> <span class="n">TypeForm</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="o">=</span> <span class="kc">None</span> <span class="c1"># OK</span>
|
||
<span class="n">ok4</span><span class="p">:</span> <span class="n">TypeForm</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="o">=</span> <span class="n">Literal</span><span class="p">[</span><span class="kc">None</span><span class="p">]</span> <span class="c1"># OK</span>
|
||
<span class="n">ok5</span><span class="p">:</span> <span class="n">TypeForm</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="o">=</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="c1"># OK</span>
|
||
<span class="n">ok6</span><span class="p">:</span> <span class="n">TypeForm</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="o">=</span> <span class="s2">"str | None"</span> <span class="c1"># OK</span>
|
||
<span class="n">ok7</span><span class="p">:</span> <span class="n">TypeForm</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="o">=</span> <span class="n">Any</span> <span class="c1"># OK</span>
|
||
|
||
<span class="n">err1</span><span class="p">:</span> <span class="n">TypeForm</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="o">=</span> <span class="nb">str</span> <span class="o">|</span> <span class="nb">int</span> <span class="c1"># Error</span>
|
||
<span class="n">err2</span><span class="p">:</span> <span class="n">TypeForm</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="o">=</span> <span class="nb">list</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="c1"># Error</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>By this same definition, <code class="docutils literal notranslate"><span class="pre">TypeForm[Any]</span></code> describes a type form object
|
||
that represents the type <code class="docutils literal notranslate"><span class="pre">Any</span></code> or any type that is assignable to <code class="docutils literal notranslate"><span class="pre">Any</span></code>.
|
||
Since all types in the Python type system are assignable to <code class="docutils literal notranslate"><span class="pre">Any</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">TypeForm[Any]</span></code> describes the set of all type form objects
|
||
evaluated from all valid type expressions.</p>
|
||
<p>The type expression <code class="docutils literal notranslate"><span class="pre">TypeForm</span></code>, with no type argument provided, is
|
||
equivalent to <code class="docutils literal notranslate"><span class="pre">TypeForm[Any]</span></code>.</p>
|
||
<section id="implicit-typeform-evaluation">
|
||
<h3><a class="toc-backref" href="#implicit-typeform-evaluation" role="doc-backlink">Implicit <code class="docutils literal notranslate"><span class="pre">TypeForm</span></code> Evaluation</a></h3>
|
||
<p>When a static type checker encounters an expression that follows all of the
|
||
syntactic, semantic and contextual rules for a type expression as detailed
|
||
in the typing spec, the evaluated type of this expression should be assignable
|
||
to <code class="docutils literal notranslate"><span class="pre">TypeForm[T]</span></code> if the type it describes is assignable to <code class="docutils literal notranslate"><span class="pre">T</span></code>.</p>
|
||
<p>For example, if a static type checker encounters the expression <code class="docutils literal notranslate"><span class="pre">str</span> <span class="pre">|</span> <span class="pre">None</span></code>,
|
||
it may normally evaluate its type as <code class="docutils literal notranslate"><span class="pre">UnionType</span></code> because it produces a
|
||
runtime value that is an instance of <code class="docutils literal notranslate"><span class="pre">types.UnionType</span></code>. However, because
|
||
this expression is a valid type expression, it is also assignable to the
|
||
type <code class="docutils literal notranslate"><span class="pre">TypeForm[str</span> <span class="pre">|</span> <span class="pre">None]</span></code>:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">v1_actual</span><span class="p">:</span> <span class="n">UnionType</span> <span class="o">=</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="c1"># OK</span>
|
||
<span class="n">v1_type_form</span><span class="p">:</span> <span class="n">TypeForm</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="o">=</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="c1"># OK</span>
|
||
|
||
<span class="n">v2_actual</span><span class="p">:</span> <span class="nb">type</span> <span class="o">=</span> <span class="nb">list</span><span class="p">[</span><span class="nb">int</span><span class="p">]</span> <span class="c1"># OK</span>
|
||
<span class="n">v2_type_form</span><span class="p">:</span> <span class="n">TypeForm</span> <span class="o">=</span> <span class="nb">list</span><span class="p">[</span><span class="nb">int</span><span class="p">]</span> <span class="c1"># OK</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">Annotated</span></code> special form is allowed in type expressions, so it can
|
||
also appear in an expression that is assignable to <code class="docutils literal notranslate"><span class="pre">TypeForm</span></code>. Consistent
|
||
with the typing spec’s rules for <code class="docutils literal notranslate"><span class="pre">Annotated</span></code>, a static type checker may choose
|
||
to ignore any <code class="docutils literal notranslate"><span class="pre">Annotated</span></code> metadata that it does not understand:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">v3</span><span class="p">:</span> <span class="n">TypeForm</span><span class="p">[</span><span class="nb">int</span> <span class="o">|</span> <span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="n">Annotated</span><span class="p">[</span><span class="nb">int</span> <span class="o">|</span> <span class="nb">str</span><span class="p">,</span> <span class="s2">"metadata"</span><span class="p">]</span> <span class="c1"># OK</span>
|
||
<span class="n">v4</span><span class="p">:</span> <span class="n">TypeForm</span><span class="p">[</span><span class="n">Annotated</span><span class="p">[</span><span class="nb">int</span> <span class="o">|</span> <span class="nb">str</span><span class="p">,</span> <span class="s2">"metadata"</span><span class="p">]]</span> <span class="o">=</span> <span class="nb">int</span> <span class="o">|</span> <span class="nb">str</span> <span class="c1"># OK</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>A string literal expression containing a valid type expression should likewise
|
||
be assignable to <code class="docutils literal notranslate"><span class="pre">TypeForm</span></code>:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">v5</span><span class="p">:</span> <span class="n">TypeForm</span><span class="p">[</span><span class="nb">set</span><span class="p">[</span><span class="nb">str</span><span class="p">]]</span> <span class="o">=</span> <span class="s2">"set[str]"</span> <span class="c1"># OK</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Expressions that violate one or more of the syntactic, semantic, or contextual
|
||
rules for type expressions should not evaluate to a <code class="docutils literal notranslate"><span class="pre">TypeForm</span></code> type. The rules
|
||
for type expression validity are explained in detail within the typing spec, so
|
||
they are not repeated here:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">bad1</span><span class="p">:</span> <span class="n">TypeForm</span> <span class="o">=</span> <span class="nb">tuple</span><span class="p">()</span> <span class="c1"># Error: Call expression not allowed in type expression</span>
|
||
<span class="n">bad2</span><span class="p">:</span> <span class="n">TypeForm</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="c1"># Error: Tuple expression not allowed in type expression</span>
|
||
<span class="n">bad3</span><span class="p">:</span> <span class="n">TypeForm</span> <span class="o">=</span> <span class="mi">1</span> <span class="c1"># Non-class object not allowed in type expression</span>
|
||
<span class="n">bad4</span><span class="p">:</span> <span class="n">TypeForm</span> <span class="o">=</span> <span class="n">Self</span> <span class="c1"># Error: Self not allowed outside of a class</span>
|
||
<span class="n">bad5</span><span class="p">:</span> <span class="n">TypeForm</span> <span class="o">=</span> <span class="n">Literal</span><span class="p">[</span><span class="n">var</span><span class="p">]</span> <span class="c1"># Error: Variable not allowed in type expression</span>
|
||
<span class="n">bad6</span><span class="p">:</span> <span class="n">TypeForm</span> <span class="o">=</span> <span class="n">Literal</span><span class="p">[</span><span class="sa">f</span><span class="s2">""</span><span class="p">]</span> <span class="c1"># Error: f-strings not allowed in type expression</span>
|
||
<span class="n">bad7</span><span class="p">:</span> <span class="n">TypeForm</span> <span class="o">=</span> <span class="n">ClassVar</span><span class="p">[</span><span class="nb">int</span><span class="p">]</span> <span class="c1"># Error: ClassVar not allowed in type expression</span>
|
||
<span class="n">bad8</span><span class="p">:</span> <span class="n">TypeForm</span> <span class="o">=</span> <span class="n">Required</span><span class="p">[</span><span class="nb">int</span><span class="p">]</span> <span class="c1"># Error: Required not allowed in type expression</span>
|
||
<span class="n">bad9</span><span class="p">:</span> <span class="n">TypeForm</span> <span class="o">=</span> <span class="n">Final</span><span class="p">[</span><span class="nb">int</span><span class="p">]</span> <span class="c1"># Error: Final not allowed in type expression</span>
|
||
<span class="n">bad10</span><span class="p">:</span> <span class="n">TypeForm</span> <span class="o">=</span> <span class="n">Unpack</span><span class="p">[</span><span class="n">Ts</span><span class="p">]</span> <span class="c1"># Error: Unpack not allowed in this context</span>
|
||
<span class="n">bad11</span><span class="p">:</span> <span class="n">TypeForm</span> <span class="o">=</span> <span class="n">Optional</span> <span class="c1"># Error: Invalid use of Optional special form</span>
|
||
<span class="n">bad12</span><span class="p">:</span> <span class="n">TypeForm</span> <span class="o">=</span> <span class="n">T</span> <span class="c1"># Error if T is an out-of-scope TypeVar</span>
|
||
<span class="n">bad13</span><span class="p">:</span> <span class="n">TypeForm</span> <span class="o">=</span> <span class="s2">"int + str"</span> <span class="c1"># Error: invalid quoted type expression</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="explicit-typeform-evaluation">
|
||
<h3><a class="toc-backref" href="#explicit-typeform-evaluation" role="doc-backlink">Explicit <code class="docutils literal notranslate"><span class="pre">TypeForm</span></code> Evaluation</a></h3>
|
||
<p><code class="docutils literal notranslate"><span class="pre">TypeForm</span></code> also acts as a function that can be called with a single argument.
|
||
Type checkers should validate that this argument is a valid type expression:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">x1</span> <span class="o">=</span> <span class="n">TypeForm</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="n">reveal_type</span><span class="p">(</span><span class="n">v1</span><span class="p">)</span> <span class="c1"># Revealed type is "TypeForm[str | None]"</span>
|
||
|
||
<span class="n">x2</span> <span class="o">=</span> <span class="n">TypeForm</span><span class="p">(</span><span class="s2">"list[int]"</span><span class="p">)</span>
|
||
<span class="n">revealed_type</span><span class="p">(</span><span class="n">v2</span><span class="p">)</span> <span class="c1"># Revealed type is "TypeForm[list[int]]"</span>
|
||
|
||
<span class="n">x3</span> <span class="o">=</span> <span class="n">TypeForm</span><span class="p">(</span><span class="s1">'type(1)'</span><span class="p">)</span> <span class="c1"># Error: invalid type expression</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>At runtime the <code class="docutils literal notranslate"><span class="pre">TypeForm(...)</span></code> callable simply returns the value passed to it.</p>
|
||
<p>This explicit syntax serves two purposes. First, it documents the developer’s
|
||
intent to use the value as a type form object. Second, static type checkers
|
||
validate that all rules for type expressions are followed:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">x4</span> <span class="o">=</span> <span class="nb">type</span><span class="p">(</span><span class="nb">int</span><span class="p">)</span> <span class="c1"># No error, evaluates to "type[int]"</span>
|
||
|
||
<span class="n">x5</span> <span class="o">=</span> <span class="n">TypeForm</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="nb">int</span><span class="p">))</span> <span class="c1"># Error: call not allowed in type expression</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="assignability">
|
||
<h3><a class="toc-backref" href="#assignability" role="doc-backlink">Assignability</a></h3>
|
||
<p><code class="docutils literal notranslate"><span class="pre">TypeForm</span></code> has a single type parameter, which is covariant. That means
|
||
<code class="docutils literal notranslate"><span class="pre">TypeForm[B]</span></code> is assignable to <code class="docutils literal notranslate"><span class="pre">TypeForm[A]</span></code> if <code class="docutils literal notranslate"><span class="pre">B</span></code> is assignable to
|
||
<code class="docutils literal notranslate"><span class="pre">A</span></code>:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">get_type_form</span><span class="p">()</span> <span class="o">-></span> <span class="n">TypeForm</span><span class="p">[</span><span class="nb">int</span><span class="p">]:</span> <span class="o">...</span>
|
||
|
||
<span class="n">t1</span><span class="p">:</span> <span class="n">TypeForm</span><span class="p">[</span><span class="nb">int</span> <span class="o">|</span> <span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="n">get_type_form</span><span class="p">()</span> <span class="c1"># OK</span>
|
||
<span class="n">t2</span><span class="p">:</span> <span class="n">TypeForm</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="n">get_type_form</span><span class="p">()</span> <span class="c1"># Error</span>
|
||
</pre></div>
|
||
</div>
|
||
<p><code class="docutils literal notranslate"><span class="pre">type[T]</span></code> is a subtype of <code class="docutils literal notranslate"><span class="pre">TypeForm[T]</span></code>, which means that <code class="docutils literal notranslate"><span class="pre">type[B]</span></code> is
|
||
assignable to <code class="docutils literal notranslate"><span class="pre">TypeForm[A]</span></code> if <code class="docutils literal notranslate"><span class="pre">B</span></code> is assignable to <code class="docutils literal notranslate"><span class="pre">A</span></code>:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">get_type</span><span class="p">()</span> <span class="o">-></span> <span class="nb">type</span><span class="p">[</span><span class="nb">int</span><span class="p">]:</span> <span class="o">...</span>
|
||
|
||
<span class="n">t3</span><span class="p">:</span> <span class="n">TypeForm</span><span class="p">[</span><span class="nb">int</span> <span class="o">|</span> <span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="n">get_type</span><span class="p">()</span> <span class="c1"># OK</span>
|
||
<span class="n">t4</span><span class="p">:</span> <span class="n">TypeForm</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="n">get_type</span><span class="p">()</span> <span class="c1"># Error</span>
|
||
</pre></div>
|
||
</div>
|
||
<p><code class="docutils literal notranslate"><span class="pre">TypeForm</span></code> is a subtype of <code class="docutils literal notranslate"><span class="pre">object</span></code> and is assumed to have all of the
|
||
attributes and methods of <code class="docutils literal notranslate"><span class="pre">object</span></code>.</p>
|
||
</section>
|
||
</section>
|
||
<section id="backward-compatibility">
|
||
<h2><a class="toc-backref" href="#backward-compatibility" role="doc-backlink">Backward Compatibility</a></h2>
|
||
<p>This PEP clarifies static type checker behaviors when evaluating type
|
||
expressions in “value expression” contexts (that is, contexts where type
|
||
expressions are not mandated by the typing spec). In the absence of a
|
||
<code class="docutils literal notranslate"><span class="pre">TypeForm</span></code> type annotation, existing type evaluation behaviors persist,
|
||
so no backward compatibility issues are anticipated. For example, if a static
|
||
type checker previously evaluated the type of expression <code class="docutils literal notranslate"><span class="pre">str</span> <span class="pre">|</span> <span class="pre">None</span></code> as
|
||
<code class="docutils literal notranslate"><span class="pre">UnionType</span></code>, it will continue to do so unless this expression is assigned
|
||
to a variable or parameter whose type is annotated as <code class="docutils literal notranslate"><span class="pre">TypeForm</span></code>.</p>
|
||
</section>
|
||
<section id="how-to-teach-this">
|
||
<h2><a class="toc-backref" href="#how-to-teach-this" role="doc-backlink">How to Teach This</a></h2>
|
||
<p>Type expressions are used in annotations to describe which values are accepted
|
||
by a function parameter, returned by a function, or stored in a variable:</p>
|
||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span> parameter type return type
|
||
| |
|
||
v v
|
||
def plus(n1: int, n2: int) -> int:
|
||
sum: int = n1 + n2
|
||
^
|
||
|
|
||
variable type
|
||
|
||
return sum
|
||
</pre></div>
|
||
</div>
|
||
<p>Type expressions evaluate to valid <em>type form</em> objects at runtime and can be
|
||
assigned to variables and manipulated like any other data in a program:</p>
|
||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span> a variable a type expression
|
||
| |
|
||
v v
|
||
int_type_form: TypeForm = int | None
|
||
^
|
||
|
|
||
the type of a type form object
|
||
</pre></div>
|
||
</div>
|
||
<p><code class="docutils literal notranslate"><span class="pre">TypeForm[]</span></code> is how you spell the type of a <em>type form</em> object, which is
|
||
a runtime representation of a type.</p>
|
||
<p><code class="docutils literal notranslate"><span class="pre">TypeForm</span></code> is similar to <code class="docutils literal notranslate"><span class="pre">type</span></code>, but <code class="docutils literal notranslate"><span class="pre">type</span></code> is compatible only with
|
||
<strong>class objects</strong> like <code class="docutils literal notranslate"><span class="pre">int</span></code>, <code class="docutils literal notranslate"><span class="pre">str</span></code>, <code class="docutils literal notranslate"><span class="pre">list</span></code>, or <code class="docutils literal notranslate"><span class="pre">MyClass</span></code>.
|
||
<code class="docutils literal notranslate"><span class="pre">TypeForm</span></code> accommodates any type form that can be expressed using
|
||
a valid type expression, including those with brackets (<code class="docutils literal notranslate"><span class="pre">list[int]</span></code>), union
|
||
operators (<code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">|</span> <span class="pre">None</span></code>), and special forms (<code class="docutils literal notranslate"><span class="pre">Any</span></code>, <code class="docutils literal notranslate"><span class="pre">LiteralString</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">Never</span></code>, etc.).</p>
|
||
<p>Most programmers will not define their <em>own</em> functions that accept a <code class="docutils literal notranslate"><span class="pre">TypeForm</span></code>
|
||
parameter or return a <code class="docutils literal notranslate"><span class="pre">TypeForm</span></code> value. It is more common to pass a type
|
||
form object to a library function that knows how to decode and use such objects.</p>
|
||
<p>For example, the <code class="docutils literal notranslate"><span class="pre">isassignable</span></code> function in the <code class="docutils literal notranslate"><span class="pre">trycast</span></code> library
|
||
can be used like Python’s built-in <code class="docutils literal notranslate"><span class="pre">isinstance</span></code> function to check whether
|
||
a value matches the shape of a particular type. <code class="docutils literal notranslate"><span class="pre">isassignable</span></code> accepts <em>any</em>
|
||
type form object as input.</p>
|
||
<ul>
|
||
<li>Yes:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">trycast</span> <span class="kn">import</span> <span class="n">isassignable</span>
|
||
|
||
<span class="k">if</span> <span class="n">isassignable</span><span class="p">(</span><span class="n">some_object</span><span class="p">,</span> <span class="n">MyTypedDict</span><span class="p">):</span> <span class="c1"># OK: MyTypedDict is a TypeForm[]</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
<li>No:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">some_object</span><span class="p">,</span> <span class="n">MyTypedDict</span><span class="p">):</span> <span class="c1"># ERROR: MyTypedDict is not a type[]</span>
|
||
<span class="o">...</span>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
</ul>
|
||
</section>
|
||
<section id="advanced-examples">
|
||
<h2><a class="toc-backref" href="#advanced-examples" role="doc-backlink">Advanced Examples</a></h2>
|
||
<p>If you want to write your own runtime type checker or a function that
|
||
manipulates type form objects as values at runtime, this section provides
|
||
examples of how such a function can use <code class="docutils literal notranslate"><span class="pre">TypeForm</span></code>.</p>
|
||
<section id="introspecting-type-form-objects">
|
||
<h3><a class="toc-backref" href="#introspecting-type-form-objects" role="doc-backlink">Introspecting type form objects</a></h3>
|
||
<p>Functions like <code class="docutils literal notranslate"><span class="pre">typing.get_origin</span></code> and <code class="docutils literal notranslate"><span class="pre">typing.get_args</span></code> can be used to
|
||
extract components of some type form objects.</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">def</span> <span class="nf">strip_annotated_metadata</span><span class="p">(</span><span class="n">typx</span><span class="p">:</span> <span class="n">TypeForm</span><span class="p">[</span><span class="n">T</span><span class="p">])</span> <span class="o">-></span> <span class="n">TypeForm</span><span class="p">[</span><span class="n">T</span><span class="p">]:</span>
|
||
<span class="k">if</span> <span class="n">typing</span><span class="o">.</span><span class="n">get_origin</span><span class="p">(</span><span class="n">typx</span><span class="p">)</span> <span class="ow">is</span> <span class="n">typing</span><span class="o">.</span><span class="n">Annotated</span><span class="p">:</span>
|
||
<span class="n">typx</span> <span class="o">=</span> <span class="n">cast</span><span class="p">(</span><span class="n">TypeForm</span><span class="p">[</span><span class="n">T</span><span class="p">],</span> <span class="n">typing</span><span class="o">.</span><span class="n">get_args</span><span class="p">(</span><span class="n">typx</span><span class="p">)[</span><span class="mi">0</span><span class="p">])</span>
|
||
<span class="k">return</span> <span class="n">typx</span>
|
||
</pre></div>
|
||
</div>
|
||
<p><code class="docutils literal notranslate"><span class="pre">isinstance</span></code> and <code class="docutils literal notranslate"><span class="pre">is</span></code> can also be used to distinguish between different
|
||
kinds of type form objects:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">types</span>
|
||
<span class="kn">import</span> <span class="nn">typing</span>
|
||
|
||
<span class="k">def</span> <span class="nf">split_union</span><span class="p">(</span><span class="n">typx</span><span class="p">:</span> <span class="n">TypeForm</span><span class="p">)</span> <span class="o">-></span> <span class="nb">tuple</span><span class="p">[</span><span class="n">TypeForm</span><span class="p">,</span> <span class="o">...</span><span class="p">]:</span>
|
||
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">typ</span><span class="p">,</span> <span class="n">types</span><span class="o">.</span><span class="n">UnionType</span><span class="p">):</span> <span class="c1"># X | Y</span>
|
||
<span class="k">return</span> <span class="n">cast</span><span class="p">(</span><span class="nb">tuple</span><span class="p">[</span><span class="n">TypeForm</span><span class="p">,</span> <span class="o">...</span><span class="p">],</span> <span class="n">typing</span><span class="o">.</span><span class="n">get_args</span><span class="p">(</span><span class="n">typ</span><span class="p">))</span>
|
||
<span class="k">if</span> <span class="n">typing</span><span class="o">.</span><span class="n">get_origin</span><span class="p">(</span><span class="n">typ</span><span class="p">)</span> <span class="ow">is</span> <span class="n">typing</span><span class="o">.</span><span class="n">Union</span><span class="p">:</span> <span class="c1"># Union[X, Y]</span>
|
||
<span class="k">return</span> <span class="n">cast</span><span class="p">(</span><span class="nb">tuple</span><span class="p">[</span><span class="n">TypeForm</span><span class="p">,</span> <span class="o">...</span><span class="p">],</span> <span class="n">typing</span><span class="o">.</span><span class="n">get_args</span><span class="p">(</span><span class="n">typ</span><span class="p">))</span>
|
||
<span class="k">if</span> <span class="n">typ</span> <span class="ow">in</span> <span class="p">(</span><span class="n">typing</span><span class="o">.</span><span class="n">Never</span><span class="p">,</span> <span class="n">typing</span><span class="o">.</span><span class="n">NoReturn</span><span class="p">,):</span>
|
||
<span class="k">return</span> <span class="p">()</span>
|
||
<span class="k">return</span> <span class="p">(</span><span class="n">typ</span><span class="p">,)</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="combining-with-a-type-variable">
|
||
<h3><a class="toc-backref" href="#combining-with-a-type-variable" role="doc-backlink">Combining with a type variable</a></h3>
|
||
<p><code class="docutils literal notranslate"><span class="pre">TypeForm</span></code> can be parameterized by a type variable that is used elsewhere
|
||
within the same function definition:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">as_instance</span><span class="p">[</span><span class="n">T</span><span class="p">](</span><span class="n">typx</span><span class="p">:</span> <span class="n">TypeForm</span><span class="p">[</span><span class="n">T</span><span class="p">])</span> <span class="o">-></span> <span class="n">T</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
|
||
<span class="k">return</span> <span class="n">typ</span><span class="p">()</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">typ</span><span class="p">,</span> <span class="nb">type</span><span class="p">)</span> <span class="k">else</span> <span class="kc">None</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="combining-with-type">
|
||
<h3><a class="toc-backref" href="#combining-with-type" role="doc-backlink">Combining with <code class="docutils literal notranslate"><span class="pre">type</span></code></a></h3>
|
||
<p>Both <code class="docutils literal notranslate"><span class="pre">TypeForm</span></code> and <code class="docutils literal notranslate"><span class="pre">type</span></code> can be parameterized by the same type
|
||
variable within the same function definition:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">as_type</span><span class="p">[</span><span class="n">T</span><span class="p">](</span><span class="n">typx</span><span class="p">:</span> <span class="n">TypeForm</span><span class="p">[</span><span class="n">T</span><span class="p">])</span> <span class="o">-></span> <span class="nb">type</span><span class="p">[</span><span class="n">T</span><span class="p">]</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
|
||
<span class="k">return</span> <span class="n">typ</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">typ</span><span class="p">,</span> <span class="nb">type</span><span class="p">)</span> <span class="k">else</span> <span class="kc">None</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="combining-with-typeis-and-typeguard">
|
||
<h3><a class="toc-backref" href="#combining-with-typeis-and-typeguard" role="doc-backlink">Combining with <code class="docutils literal notranslate"><span class="pre">TypeIs</span></code> and <code class="docutils literal notranslate"><span class="pre">TypeGuard</span></code></a></h3>
|
||
<p>A type variable can also be used by a <code class="docutils literal notranslate"><span class="pre">TypeIs</span></code> or <code class="docutils literal notranslate"><span class="pre">TypeGuard</span></code> return type:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">isassignable</span><span class="p">[</span><span class="n">T</span><span class="p">](</span><span class="n">value</span><span class="p">:</span> <span class="nb">object</span><span class="p">,</span> <span class="n">typx</span><span class="p">:</span> <span class="n">TypeForm</span><span class="p">[</span><span class="n">T</span><span class="p">])</span> <span class="o">-></span> <span class="n">TypeIs</span><span class="p">[</span><span class="n">T</span><span class="p">]:</span> <span class="o">...</span>
|
||
|
||
<span class="n">count</span><span class="p">:</span> <span class="nb">int</span> <span class="o">|</span> <span class="nb">str</span> <span class="o">=</span> <span class="o">...</span>
|
||
<span class="k">if</span> <span class="n">isassignable</span><span class="p">(</span><span class="n">count</span><span class="p">,</span> <span class="nb">int</span><span class="p">):</span>
|
||
<span class="n">assert_type</span><span class="p">(</span><span class="n">count</span><span class="p">,</span> <span class="nb">int</span><span class="p">)</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="n">assert_type</span><span class="p">(</span><span class="n">count</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="challenges-when-accepting-all-typeforms">
|
||
<h3><a class="toc-backref" href="#challenges-when-accepting-all-typeforms" role="doc-backlink">Challenges When Accepting All TypeForms</a></h3>
|
||
<p>A function that takes an <em>arbitrary</em> <code class="docutils literal notranslate"><span class="pre">TypeForm</span></code> as input must support a
|
||
variety of possible type form objects. Such functions are not easy to write.</p>
|
||
<ul class="simple">
|
||
<li>New special forms are introduced with each new Python version, and
|
||
special handling may be required for each one.</li>
|
||
<li>Quoted annotations <a class="footnote-reference brackets" href="#quoted-less-common" id="id2">[5]</a> (like <code class="docutils literal notranslate"><span class="pre">'list[str]'</span></code>)
|
||
must be <em>parsed</em> (to something like <code class="docutils literal notranslate"><span class="pre">list[str]</span></code>).</li>
|
||
<li>Resolving quoted forward references inside type expressions is typically
|
||
done with <code class="docutils literal notranslate"><span class="pre">eval()</span></code>, which is difficult to use in a safe way.</li>
|
||
<li>Recursive types like <code class="docutils literal notranslate"><span class="pre">IntTree</span> <span class="pre">=</span> <span class="pre">list[int</span> <span class="pre">|</span> <span class="pre">'IntTree']</span></code> are difficult
|
||
to resolve.</li>
|
||
<li>User-defined generic types (like Django’s <code class="docutils literal notranslate"><span class="pre">QuerySet[User]</span></code>) can introduce
|
||
non-standard behaviors that require runtime support.</li>
|
||
</ul>
|
||
</section>
|
||
</section>
|
||
<section id="reference-implementation">
|
||
<h2><a class="toc-backref" href="#reference-implementation" role="doc-backlink">Reference Implementation</a></h2>
|
||
<p>Pyright (version 1.1.379) provides a reference implementation for <code class="docutils literal notranslate"><span class="pre">TypeForm</span></code>.</p>
|
||
<p>Mypy contributors also <a class="reference external" href="https://github.com/python/mypy/issues/9773">plan to implement</a>
|
||
support for <code class="docutils literal notranslate"><span class="pre">TypeForm</span></code>.</p>
|
||
<p>A reference implementation of the runtime component is provided in the
|
||
<code class="docutils literal notranslate"><span class="pre">typing_extensions</span></code> module.</p>
|
||
</section>
|
||
<section id="rejected-ideas">
|
||
<h2><a class="toc-backref" href="#rejected-ideas" role="doc-backlink">Rejected Ideas</a></h2>
|
||
<section id="alternative-names">
|
||
<h3><a class="toc-backref" href="#alternative-names" role="doc-backlink">Alternative names</a></h3>
|
||
<p>Alternate names were considered for <code class="docutils literal notranslate"><span class="pre">TypeForm</span></code>. <code class="docutils literal notranslate"><span class="pre">TypeObject</span></code>
|
||
and <code class="docutils literal notranslate"><span class="pre">TypeType</span></code> were deemed too generic. <code class="docutils literal notranslate"><span class="pre">TypeExpression</span></code> and <code class="docutils literal notranslate"><span class="pre">TypeExpr</span></code>
|
||
were also considered, but these were considered confusing because these objects
|
||
are not themselves “expressions” but rather the result of evaluating a type
|
||
expression.</p>
|
||
</section>
|
||
<section id="widen-type-c-to-support-all-type-expressions">
|
||
<h3><a class="toc-backref" href="#widen-type-c-to-support-all-type-expressions" role="doc-backlink">Widen <code class="docutils literal notranslate"><span class="pre">type[C]</span></code> to support all type expressions</a></h3>
|
||
<p><code class="docutils literal notranslate"><span class="pre">type</span></code> was <a class="reference external" href="https://mail.python.org/archives/list/typing-sig@python.org/message/D5FHORQVPHX3BHUDGF3A3TBZURBXLPHD/">designed</a> to describe class objects, subclasses of the
|
||
<code class="docutils literal notranslate"><span class="pre">type</span></code> class. A value with the type <code class="docutils literal notranslate"><span class="pre">type</span></code> is assumed to be instantiable
|
||
through a constructor call. Widening the meaning of <code class="docutils literal notranslate"><span class="pre">type</span></code> to represent
|
||
arbitrary type form objects would present backward compatibility problems
|
||
and would eliminate a way to describe the set of values limited to subclasses
|
||
of <code class="docutils literal notranslate"><span class="pre">type</span></code>.</p>
|
||
</section>
|
||
<section id="accept-arbitrary-annotation-expressions">
|
||
<h3><a class="toc-backref" href="#accept-arbitrary-annotation-expressions" role="doc-backlink">Accept arbitrary annotation expressions</a></h3>
|
||
<p>Certain special forms act as type qualifiers and can be used in
|
||
<em>some</em> but not <em>all</em> annotation contexts:</p>
|
||
<p>For example. the type qualifier <code class="docutils literal notranslate"><span class="pre">Final</span></code> can be used as a variable type but
|
||
not as a parameter type or a return type:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">some_const</span><span class="p">:</span> <span class="n">Final</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="o">...</span> <span class="c1"># OK</span>
|
||
|
||
<span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="n">not_reassignable</span><span class="p">:</span> <span class="n">Final</span><span class="p">[</span><span class="nb">object</span><span class="p">]):</span> <span class="o">...</span> <span class="c1"># Error: Final not allowed here</span>
|
||
|
||
<span class="k">def</span> <span class="nf">nonsense</span><span class="p">()</span> <span class="o">-></span> <span class="n">Final</span><span class="p">[</span><span class="nb">object</span><span class="p">]:</span> <span class="o">...</span> <span class="c1"># Error: Final not alowed here</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>With the exception of <code class="docutils literal notranslate"><span class="pre">Annotated</span></code>, type qualifiers are not allowed in type
|
||
expressions. <code class="docutils literal notranslate"><span class="pre">TypeForm</span></code> is limited to type expressions because its
|
||
assignability rules are based on the assignability rules for types. It is
|
||
nonsensical to ask whether <code class="docutils literal notranslate"><span class="pre">Final[int]</span></code> is assignable to <code class="docutils literal notranslate"><span class="pre">int</span></code> because the
|
||
former is not a valid type expression.</p>
|
||
<p>Functions that wish to operate on objects that are evaluated from annotation
|
||
expressions can continue to accept such inputs as <code class="docutils literal notranslate"><span class="pre">object</span></code> parameters.</p>
|
||
</section>
|
||
<section id="pattern-matching-on-type-forms">
|
||
<h3><a class="toc-backref" href="#pattern-matching-on-type-forms" role="doc-backlink">Pattern matching on type forms</a></h3>
|
||
<p>It was asserted that some functions may wish to pattern match on the
|
||
interior of type expressions in their signatures.</p>
|
||
<p>One use case is to allow a function to explicitly enumerate all the
|
||
<em>specific</em> kinds of type expressions it supports as input.
|
||
Consider the following possible pattern matching syntax:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@overload</span>
|
||
<span class="k">def</span> <span class="nf">checkcast</span><span class="p">(</span><span class="n">typx</span><span class="p">:</span> <span class="n">TypeForm</span><span class="p">[</span><span class="n">AT</span><span class="o">=</span><span class="n">Annotated</span><span class="p">[</span><span class="n">T</span><span class="p">,</span> <span class="o">*</span><span class="n">A</span><span class="p">]],</span> <span class="n">value</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="n">T</span><span class="p">:</span> <span class="o">...</span>
|
||
<span class="nd">@overload</span>
|
||
<span class="k">def</span> <span class="nf">checkcast</span><span class="p">(</span><span class="n">typx</span><span class="p">:</span> <span class="n">TypeForm</span><span class="p">[</span><span class="n">UT</span><span class="o">=</span><span class="n">Union</span><span class="p">[</span><span class="o">*</span><span class="n">Ts</span><span class="p">]],</span> <span class="n">value</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="n">Union</span><span class="p">[</span><span class="o">*</span><span class="n">Ts</span><span class="p">]:</span> <span class="o">...</span>
|
||
<span class="nd">@overload</span>
|
||
<span class="k">def</span> <span class="nf">checkcast</span><span class="p">(</span><span class="n">typx</span><span class="p">:</span> <span class="nb">type</span><span class="p">[</span><span class="n">C</span><span class="p">],</span> <span class="n">value</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="n">C</span><span class="p">:</span> <span class="o">...</span>
|
||
<span class="c1"># ... (more)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>All functions observed in the wild that conceptually accept type form
|
||
objects generally try to support <em>all</em> kinds of type expressions, so it
|
||
doesn’t seem valuable to enumerate a particular subset.</p>
|
||
<p>Additionally, the above syntax isn’t precise enough to fully describe the
|
||
input constraints for a typical function in the wild. For example, many
|
||
functions do not support type expressions with quoted subexpressions
|
||
like <code class="docutils literal notranslate"><span class="pre">list['Movie']</span></code>.</p>
|
||
<p>A second use case for pattern matching is to explicitly match an <code class="docutils literal notranslate"><span class="pre">Annotated</span></code>
|
||
form to extract the interior type argument and strip away any metadata:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">checkcast</span><span class="p">(</span>
|
||
<span class="n">typx</span><span class="p">:</span> <span class="n">TypeForm</span><span class="p">[</span><span class="n">T</span><span class="p">]</span> <span class="o">|</span> <span class="n">TypeForm</span><span class="p">[</span><span class="n">AT</span><span class="o">=</span><span class="n">Annotated</span><span class="p">[</span><span class="n">T</span><span class="p">,</span> <span class="o">*</span><span class="n">A</span><span class="p">]],</span>
|
||
<span class="n">value</span><span class="p">:</span> <span class="nb">object</span>
|
||
<span class="p">)</span> <span class="o">-></span> <span class="n">T</span><span class="p">:</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>However, <code class="docutils literal notranslate"><span class="pre">Annotated[T,</span> <span class="pre">metadata]</span></code> is already treated equivalent to <code class="docutils literal notranslate"><span class="pre">T</span></code>
|
||
by static type checkers. There’s no additional value in being explicit about
|
||
this behavior. The example above could more simply be written as the equivalent:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">checkcast</span><span class="p">(</span><span class="n">typx</span><span class="p">:</span> <span class="n">TypeForm</span><span class="p">[</span><span class="n">T</span><span class="p">],</span> <span class="n">value</span><span class="p">:</span> <span class="nb">object</span><span class="p">)</span> <span class="o">-></span> <span class="n">T</span><span class="p">:</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
</section>
|
||
<section id="footnotes">
|
||
<h2><a class="toc-backref" href="#footnotes" role="doc-backlink">Footnotes</a></h2>
|
||
<aside class="footnote-list brackets">
|
||
<aside class="footnote brackets" id="type-t" role="doc-footnote">
|
||
<dt class="label" id="type-t">[1]</dt>
|
||
<dd><a class="reference external" href="https://typing.readthedocs.io/en/latest/spec/special-types.html#type-brackets" title="(in typing)"><span class="xref std std-ref">Type[T]</span></a> spells a class object</aside>
|
||
<aside class="footnote brackets" id="typeis" role="doc-footnote">
|
||
<dt class="label" id="typeis">[2]</dt>
|
||
<dd><a class="reference external" href="https://typing.readthedocs.io/en/latest/spec/narrowing.html#typeis" title="(in typing)"><span class="xref std std-ref">TypeIs[T]</span></a> is similar to bool</aside>
|
||
<aside class="footnote brackets" id="dataclassinitvar" role="doc-footnote">
|
||
<dt class="label" id="dataclassinitvar">[<a href="#id1">3</a>]</dt>
|
||
<dd><code class="docutils literal notranslate"><span class="pre">dataclass.make_dataclass</span></code> allows the type qualifier <code class="docutils literal notranslate"><span class="pre">InitVar[...]</span></code>,
|
||
so <code class="docutils literal notranslate"><span class="pre">TypeForm</span></code> cannot be used in this case.</aside>
|
||
<aside class="footnote brackets" id="forward-ref-normalization" role="doc-footnote">
|
||
<dt class="label" id="forward-ref-normalization">[4]</dt>
|
||
<dd>Special forms normalize string arguments to <code class="docutils literal notranslate"><span class="pre">ForwardRef</span></code> instances
|
||
at runtime using internal helper functions in the <code class="docutils literal notranslate"><span class="pre">typing</span></code> module.
|
||
Runtime type checkers may wish to implement similar functions when
|
||
working with string-based forward references.</aside>
|
||
<aside class="footnote brackets" id="quoted-less-common" role="doc-footnote">
|
||
<dt class="label" id="quoted-less-common">[<a href="#id2">5</a>]</dt>
|
||
<dd>Quoted annotations are expected to become less common starting in Python
|
||
3.14 when <a class="pep reference internal" href="../pep-0649/" title="PEP 649 – Deferred Evaluation Of Annotations Using Descriptors">deferred annotations</a> is implemented. However,
|
||
code written for earlier Python versions relies on quoted annotations and
|
||
will need to be supported for several years.</aside>
|
||
</aside>
|
||
</section>
|
||
<section id="copyright">
|
||
<h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2>
|
||
<p>This document is placed in the public domain or under the
|
||
CC0-1.0-Universal license, whichever is more permissive.</p>
|
||
</section>
|
||
</section>
|
||
<hr class="docutils" />
|
||
<p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0747.rst">https://github.com/python/peps/blob/main/peps/pep-0747.rst</a></p>
|
||
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0747.rst">2024-09-29 12:39:10 GMT</a></p>
|
||
|
||
</article>
|
||
<nav id="pep-sidebar">
|
||
<h2>Contents</h2>
|
||
<ul>
|
||
<li><a class="reference internal" href="#abstract">Abstract</a></li>
|
||
<li><a class="reference internal" href="#motivation">Motivation</a><ul>
|
||
<li><a class="reference internal" href="#why-not-type-c">Why not <code class="docutils literal notranslate"><span class="pre">type[C]</span></code>?</a></li>
|
||
<li><a class="reference internal" href="#typeform-use-cases">TypeForm use cases</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#specification">Specification</a><ul>
|
||
<li><a class="reference internal" href="#implicit-typeform-evaluation">Implicit <code class="docutils literal notranslate"><span class="pre">TypeForm</span></code> Evaluation</a></li>
|
||
<li><a class="reference internal" href="#explicit-typeform-evaluation">Explicit <code class="docutils literal notranslate"><span class="pre">TypeForm</span></code> Evaluation</a></li>
|
||
<li><a class="reference internal" href="#assignability">Assignability</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#backward-compatibility">Backward Compatibility</a></li>
|
||
<li><a class="reference internal" href="#how-to-teach-this">How to Teach This</a></li>
|
||
<li><a class="reference internal" href="#advanced-examples">Advanced Examples</a><ul>
|
||
<li><a class="reference internal" href="#introspecting-type-form-objects">Introspecting type form objects</a></li>
|
||
<li><a class="reference internal" href="#combining-with-a-type-variable">Combining with a type variable</a></li>
|
||
<li><a class="reference internal" href="#combining-with-type">Combining with <code class="docutils literal notranslate"><span class="pre">type</span></code></a></li>
|
||
<li><a class="reference internal" href="#combining-with-typeis-and-typeguard">Combining with <code class="docutils literal notranslate"><span class="pre">TypeIs</span></code> and <code class="docutils literal notranslate"><span class="pre">TypeGuard</span></code></a></li>
|
||
<li><a class="reference internal" href="#challenges-when-accepting-all-typeforms">Challenges When Accepting All TypeForms</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li>
|
||
<li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul>
|
||
<li><a class="reference internal" href="#alternative-names">Alternative names</a></li>
|
||
<li><a class="reference internal" href="#widen-type-c-to-support-all-type-expressions">Widen <code class="docutils literal notranslate"><span class="pre">type[C]</span></code> to support all type expressions</a></li>
|
||
<li><a class="reference internal" href="#accept-arbitrary-annotation-expressions">Accept arbitrary annotation expressions</a></li>
|
||
<li><a class="reference internal" href="#pattern-matching-on-type-forms">Pattern matching on type forms</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#footnotes">Footnotes</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-0747.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> |