CINXE.COM

PEP 764 – Inlined typed dictionaries | peps.python.org

<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="color-scheme" content="light dark"> <title>PEP 764 – Inlined typed dictionaries | peps.python.org</title> <link rel="shortcut icon" href="../_static/py.png"> <link rel="canonical" href="https://peps.python.org/pep-0764/"> <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 764 – Inlined typed dictionaries | peps.python.org'> <meta property="og:description" content="PEP 589 defines a class-based and a functional syntax to create typed dictionaries. In both scenarios, it requires defining a class or assigning to a value. In some situations, this can add unnecessary boilerplate, especially if the typed dictionary is ..."> <meta property="og:type" content="website"> <meta property="og:url" content="https://peps.python.org/pep-0764/"> <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 589 defines a class-based and a functional syntax to create typed dictionaries. In both scenarios, it requires defining a class or assigning to a value. In some situations, this can add unnecessary boilerplate, especially if the typed dictionary is ..."> <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 764</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 764 – Inlined typed dictionaries</h1> <dl class="rfc2822 field-list simple"> <dt class="field-odd">Author<span class="colon">:</span></dt> <dd class="field-odd">Victorien Plot &lt;contact&#32;&#97;t&#32;vctrn.dev&gt;</dd> <dt class="field-even">Sponsor<span class="colon">:</span></dt> <dd class="field-even">Eric Traut &lt;erictr at microsoft.com&gt;</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/78779">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">25-Oct-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/78779" title="Discourse thread">29-Jan-2025</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></li> <li><a class="reference internal" href="#rationale">Rationale</a></li> <li><a class="reference internal" href="#specification">Specification</a><ul> <li><a class="reference internal" href="#typing-specification-changes">Typing specification changes</a></li> <li><a class="reference internal" href="#id1">Runtime behavior</a></li> </ul> </li> <li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a></li> <li><a class="reference internal" href="#security-implications">Security Implications</a></li> <li><a class="reference internal" href="#how-to-teach-this">How to Teach This</a></li> <li><a class="reference internal" href="#reference-implementation">Reference Implementation</a><ul> <li><a class="reference internal" href="#runtime-implementation">Runtime implementation</a></li> </ul> </li> <li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul> <li><a class="reference internal" href="#using-the-functional-syntax-in-annotations">Using the functional syntax in annotations</a></li> <li><a class="reference internal" href="#using-dict-or-typing-dict-with-a-single-type-argument">Using <code class="docutils literal notranslate"><span class="pre">dict</span></code> or <code class="docutils literal notranslate"><span class="pre">typing.Dict</span></code> with a single type argument</a></li> <li><a class="reference internal" href="#using-a-simple-dictionary">Using a simple dictionary</a></li> <li><a class="reference internal" href="#extending-other-typed-dictionaries">Extending other typed dictionaries</a></li> </ul> </li> <li><a class="reference internal" href="#open-issues">Open Issues</a><ul> <li><a class="reference internal" href="#should-inlined-typed-dictionaries-be-proper-classes">Should inlined typed dictionaries be proper classes?</a></li> <li><a class="reference internal" href="#inlined-typed-dictionaries-and-extra-items">Inlined typed dictionaries and extra items</a></li> </ul> </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-0589/" title="PEP 589 – TypedDict: Type Hints for Dictionaries with a Fixed Set of Keys">PEP 589</a> defines a <a class="reference external" href="https://typing.python.org/en/latest/spec/typeddict.html#typeddict-class-based-syntax" title="(in typing)"><span class="xref std std-ref">class-based</span></a> and a <a class="reference external" href="https://typing.python.org/en/latest/spec/typeddict.html#typeddict-functional-syntax" title="(in typing)"><span class="xref std std-ref">functional syntax</span></a> to create typed dictionaries. In both scenarios, it requires defining a class or assigning to a value. In some situations, this can add unnecessary boilerplate, especially if the typed dictionary is only used once.</p> <p>This PEP proposes the addition of a new inlined syntax, by subscripting the <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.TypedDict" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">TypedDict</span></code></a> type:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">TypedDict</span> <span class="k">def</span><span class="w"> </span><span class="nf">get_movie</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="n">TypedDict</span><span class="p">[{</span><span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="s1">&#39;year&#39;</span><span class="p">:</span> <span class="nb">int</span><span class="p">}]:</span> <span class="k">return</span> <span class="p">{</span> <span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="s1">&#39;Blade Runner&#39;</span><span class="p">,</span> <span class="s1">&#39;year&#39;</span><span class="p">:</span> <span class="mi">1982</span><span class="p">,</span> <span class="p">}</span> </pre></div> </div> </section> <section id="motivation"> <h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2> <p>Python dictionaries are an essential data structure of the language. Many times, it is used to return or accept structured data in functions. However, it can get tedious to define <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.TypedDict" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">TypedDict</span></code></a> classes:</p> <ul class="simple"> <li>A typed dictionary requires a name, which might not be relevant.</li> <li>Nested dictionaries require more than one class definition.</li> </ul> <p>Taking a simple function returning some nested structured data as an example:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">TypedDict</span> <span class="k">class</span><span class="w"> </span><span class="nc">ProductionCompany</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span> <span class="n">location</span><span class="p">:</span> <span class="nb">str</span> <span class="k">class</span><span class="w"> </span><span class="nc">Movie</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span> <span class="n">year</span><span class="p">:</span> <span class="nb">int</span> <span class="n">production</span><span class="p">:</span> <span class="n">ProductionCompany</span> <span class="k">def</span><span class="w"> </span><span class="nf">get_movie</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="n">Movie</span><span class="p">:</span> <span class="k">return</span> <span class="p">{</span> <span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="s1">&#39;Blade Runner&#39;</span><span class="p">,</span> <span class="s1">&#39;year&#39;</span><span class="p">:</span> <span class="mi">1982</span><span class="p">,</span> <span class="s1">&#39;production&#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;Warner Bros.&#39;</span><span class="p">,</span> <span class="s1">&#39;location&#39;</span><span class="p">:</span> <span class="s1">&#39;California&#39;</span><span class="p">,</span> <span class="p">}</span> <span class="p">}</span> </pre></div> </div> </section> <section id="rationale"> <h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2> <p>The new inlined syntax can be used to resolve these problems:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">get_movie</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="n">TypedDict</span><span class="p">[{</span><span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="s1">&#39;year&#39;</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="s1">&#39;production&#39;</span><span class="p">:</span> <span class="n">TypedDict</span><span class="p">[{</span><span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="s1">&#39;location&#39;</span><span class="p">:</span> <span class="nb">str</span><span class="p">}]}]:</span> <span class="o">...</span> </pre></div> </div> <p>While less useful (as the functional or even the class-based syntax can be used), inlined typed dictionaries can be assigned to a variable, as an alias:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">InlinedTD</span> <span class="o">=</span> <span class="n">TypedDict</span><span class="p">[{</span><span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="nb">str</span><span class="p">}]</span> <span class="k">def</span><span class="w"> </span><span class="nf">get_movie</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="n">InlinedTD</span><span class="p">:</span> <span class="o">...</span> </pre></div> </div> </section> <section id="specification"> <h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2> <p>The <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.TypedDict" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">TypedDict</span></code></a> special form is made subscriptable, and accepts a single type argument which must be a <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#dict" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">dict</span></code></a>, following the same semantics as the <a class="reference external" href="https://typing.python.org/en/latest/spec/typeddict.html#typeddict-functional-syntax" title="(in typing)"><span class="xref std std-ref">functional syntax</span></a> (the dictionary keys are strings representing the field names, and values are valid <a class="reference external" href="https://typing.python.org/en/latest/spec/annotations.html#annotation-expression" title="(in typing)"><span class="xref std std-ref">annotation expressions</span></a>). Only the comma-separated list of <code class="docutils literal notranslate"><span class="pre">key:</span> <span class="pre">value</span></code> pairs within braces constructor (<code class="docutils literal notranslate"><span class="pre">{k:</span> <span class="pre">&lt;type&gt;}</span></code>) is allowed, and should be specified directly as the type argument (i.e. it is not allowed to use a variable which was previously assigned a <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#dict" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">dict</span></code></a> instance).</p> <p>Inlined typed dictionaries can be referred to as <em>anonymous</em>, meaning they don’t have a specific name (see the <a class="reference external" href="Runtimebehavior">runtime behavior</a> section).</p> <p>It is possible to define a nested inlined dictionary:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Movie</span> <span class="o">=</span> <span class="n">TypedDict</span><span class="p">[{</span><span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="s1">&#39;production&#39;</span><span class="p">:</span> <span class="n">TypedDict</span><span class="p">[{</span><span class="s1">&#39;location&#39;</span><span class="p">:</span> <span class="nb">str</span><span class="p">}]}]</span> <span class="c1"># Note that the following is invalid as per the updated `type_expression` grammar:</span> <span class="n">Movie</span> <span class="o">=</span> <span class="n">TypedDict</span><span class="p">[{</span><span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="s1">&#39;production&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;location&#39;</span><span class="p">:</span> <span class="nb">str</span><span class="p">}}]</span> </pre></div> </div> <p>Although it is not possible to specify any class arguments such as <code class="docutils literal notranslate"><span class="pre">total</span></code>, any <a class="reference external" href="https://typing.python.org/en/latest/spec/glossary.html#term-type-qualifier" title="(in typing)"><span>type qualifier</span></a> can be used for individual fields:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Movie</span> <span class="o">=</span> <span class="n">TypedDict</span><span class="p">[{</span><span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="n">NotRequired</span><span class="p">[</span><span class="nb">str</span><span class="p">],</span> <span class="s1">&#39;year&#39;</span><span class="p">:</span> <span class="n">ReadOnly</span><span class="p">[</span><span class="nb">int</span><span class="p">]}]</span> </pre></div> </div> <p>Inlined typed dictionaries are implicitly <em>total</em>, meaning all keys must be present. Using the <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.Required" title="(in Python v3.13)"><code class="xref py py-data docutils literal notranslate"><span class="pre">Required</span></code></a> type qualifier is thus redundant.</p> <p>Type variables are allowed in inlined typed dictionaries, provided that they are bound to some outer scope:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">C</span><span class="p">[</span><span class="n">T</span><span class="p">]:</span> <span class="n">inlined_td</span><span class="p">:</span> <span class="n">TypedDict</span><span class="p">[{</span><span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="n">T</span><span class="p">}]</span> <span class="c1"># OK, `T` is scoped to the class `C`.</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">C</span><span class="p">[</span><span class="nb">int</span><span class="p">]()</span><span class="o">.</span><span class="n">inlined_td</span><span class="p">[</span><span class="s1">&#39;name&#39;</span><span class="p">])</span> <span class="c1"># Revealed type is &#39;int&#39;</span> <span class="k">def</span><span class="w"> </span><span class="nf">fn</span><span class="p">[</span><span class="n">T</span><span class="p">](</span><span class="n">arg</span><span class="p">:</span> <span class="n">T</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">TypedDict</span><span class="p">[{</span><span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="n">T</span><span class="p">}]:</span> <span class="o">...</span> <span class="c1"># OK: `T` is scoped to the function `fn`.</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">fn</span><span class="p">(</span><span class="s1">&#39;a&#39;</span><span class="p">)[</span><span class="s1">&#39;name&#39;</span><span class="p">])</span> <span class="c1"># Revealed type is &#39;str&#39;</span> <span class="nb">type</span> <span class="n">InlinedTD</span><span class="p">[</span><span class="n">T</span><span class="p">]</span> <span class="o">=</span> <span class="n">TypedDict</span><span class="p">[{</span><span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="n">T</span><span class="p">}]</span> <span class="c1"># OK, `T` is scoped to the type alias.</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">InlinedTD</span> <span class="o">=</span> <span class="n">TypedDict</span><span class="p">[{</span><span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="n">T</span><span class="p">}]</span> <span class="c1"># OK, same as the previous type alias, but using the old-style syntax.</span> <span class="k">def</span><span class="w"> </span><span class="nf">func</span><span class="p">():</span> <span class="n">InlinedTD</span> <span class="o">=</span> <span class="n">TypedDict</span><span class="p">[{</span><span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="n">T</span><span class="p">}]</span> <span class="c1"># Not OK: `T` refers to a type variable that is not bound to the scope of `func`.</span> </pre></div> </div> <section id="typing-specification-changes"> <h3><a class="toc-backref" href="#typing-specification-changes" role="doc-backlink">Typing specification changes</a></h3> <p>The inlined typed dictionary adds a new kind of <a class="reference external" href="https://typing.python.org/en/latest/spec/glossary.html#term-type-expression" title="(in typing)"><span>type expression</span></a>. As such, the <a class="reference external" href="https://typing.python.org/en/latest/spec/annotations.html#grammar-token-expression-grammar-type_expression" title="(in typing)"><code class="xref std std-token docutils literal notranslate"><span class="pre">type_expression</span></code></a> production will be updated to include the inlined syntax:</p> <pre> <strong id="grammar-token-inlined-typed-dictionaries-grammar-new-type_expression">new-type_expression</strong> ::= <a class="reference external" href="https://typing.python.org/en/latest/spec/annotations.html#grammar-token-expression-grammar-type_expression" title="(in typing)"><code class="xref docutils literal notranslate"><span class="pre">type_expression</span></code></a> | &lt;TypedDict&gt; '[' '{' (string: ':' <a class="reference external" href="https://typing.python.org/en/latest/spec/annotations.html#grammar-token-expression-grammar-annotation_expression" title="(in typing)"><code class="xref docutils literal notranslate"><span class="pre">annotation_expression</span></code></a> ',')* '}' ']' (where string is any string literal) </pre> </section> <section id="id1"> <h3><a class="toc-backref" href="#id1" role="doc-backlink">Runtime behavior</a></h3> <p>Although <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.TypedDict" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">TypedDict</span></code></a> is commonly referred as a class, it is implemented as a function at runtime. To be made subscriptable, it will be changed to be a class.</p> <p>Creating an inlined typed dictionary results in a new class, so <code class="docutils literal notranslate"><span class="pre">T1</span></code> and <code class="docutils literal notranslate"><span class="pre">T2</span></code> are of the same type:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">TypedDict</span> <span class="n">T1</span> <span class="o">=</span> <span class="n">TypedDict</span><span class="p">(</span><span class="s1">&#39;T1&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;a&#39;</span><span class="p">:</span> <span class="nb">int</span><span class="p">})</span> <span class="n">T2</span> <span class="o">=</span> <span class="n">TypedDict</span><span class="p">[{</span><span class="s1">&#39;a&#39;</span><span class="p">:</span> <span class="nb">int</span><span class="p">}]</span> </pre></div> </div> <p>As inlined typed dictionaries are are meant to be <em>anonymous</em>, their <a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#type.__name__" title="(in Python v3.13)"><code class="xref py py-attr docutils literal notranslate"><span class="pre">__name__</span></code></a> attribute will be set to an empty string.</p> </section> </section> <section id="backwards-compatibility"> <h2><a class="toc-backref" href="#backwards-compatibility" role="doc-backlink">Backwards Compatibility</a></h2> <p>This PEP does not bring any backwards incompatible changes.</p> </section> <section id="security-implications"> <h2><a class="toc-backref" href="#security-implications" role="doc-backlink">Security Implications</a></h2> <p>There are no known security consequences arising from this PEP.</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>The new inlined syntax will be documented both in the <a class="reference external" href="https://docs.python.org/3/library/typing.html#module-typing" title="(in Python v3.13)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">typing</span></code></a> module documentation and the <a class="reference external" href="https://typing.python.org/en/latest/spec/typeddict.html#typed-dictionaries" title="(in typing)"><span class="xref std std-ref">typing specification</span></a>.</p> <p>When complex dictionary structures are used, having everything defined on a single line can hurt readability. Code formatters can help by formatting the inlined typed dictionary across multiple lines:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">edit_movie</span><span class="p">(</span> <span class="n">movie</span><span class="p">:</span> <span class="n">TypedDict</span><span class="p">[{</span> <span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="s1">&#39;year&#39;</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="s1">&#39;production&#39;</span><span class="p">:</span> <span class="n">TypedDict</span><span class="p">[{</span> <span class="s1">&#39;location&#39;</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="p">}],</span> <span class="p">}],</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> </section> <section id="reference-implementation"> <h2><a class="toc-backref" href="#reference-implementation" role="doc-backlink">Reference Implementation</a></h2> <p>Mypy supports a similar syntax as an <a class="reference external" href="https://mypy.readthedocs.io/en/latest/command_line.html#cmdoption-mypy-enable-incomplete-feature" title="(in mypy v1.16.0+dev.f6295899f4bcda61dc4017fabdb9c85c844bcc53)"><code class="xref std std-option docutils literal notranslate"><span class="pre">experimental</span> <span class="pre">feature</span></code></a>:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">test_values</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="p">{</span><span class="s2">&quot;int&quot;</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="s2">&quot;str&quot;</span><span class="p">:</span> <span class="nb">str</span><span class="p">}:</span> <span class="k">return</span> <span class="p">{</span><span class="s2">&quot;int&quot;</span><span class="p">:</span> <span class="mi">42</span><span class="p">,</span> <span class="s2">&quot;str&quot;</span><span class="p">:</span> <span class="s2">&quot;test&quot;</span><span class="p">}</span> </pre></div> </div> <p>Pyright added support for the new syntax in version <a class="reference external" href="https://github.com/microsoft/pyright/releases/tag/1.1.387">1.1.387</a>.</p> <section id="runtime-implementation"> <h3><a class="toc-backref" href="#runtime-implementation" role="doc-backlink">Runtime implementation</a></h3> <p>A draft implementation is available <a class="reference external" href="https://github.com/Viicos/cpython/commit/49e5a83f">here</a>.</p> </section> </section> <section id="rejected-ideas"> <h2><a class="toc-backref" href="#rejected-ideas" role="doc-backlink">Rejected Ideas</a></h2> <section id="using-the-functional-syntax-in-annotations"> <h3><a class="toc-backref" href="#using-the-functional-syntax-in-annotations" role="doc-backlink">Using the functional syntax in annotations</a></h3> <p>The alternative functional syntax could be used as an annotation directly:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">get_movie</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="n">TypedDict</span><span class="p">(</span><span class="s1">&#39;Movie&#39;</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="nb">str</span><span class="p">}):</span> <span class="o">...</span> </pre></div> </div> <p>However, call expressions are currently unsupported in such a context for various reasons (expensive to process, evaluating them is not standardized).</p> <p>This would also require a name which is sometimes not relevant.</p> </section> <section id="using-dict-or-typing-dict-with-a-single-type-argument"> <h3><a class="toc-backref" href="#using-dict-or-typing-dict-with-a-single-type-argument" role="doc-backlink">Using <code class="docutils literal notranslate"><span class="pre">dict</span></code> or <code class="docutils literal notranslate"><span class="pre">typing.Dict</span></code> with a single type argument</a></h3> <p>We could reuse <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#dict" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">dict</span></code></a> or <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.Dict" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">typing.Dict</span></code></a> with a single type argument to express the same concept:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">get_movie</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">[{</span><span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="nb">str</span><span class="p">}]:</span> <span class="o">...</span> </pre></div> </div> <p>While this would avoid having to import <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.TypedDict" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">TypedDict</span></code></a> from <a class="reference external" href="https://docs.python.org/3/library/typing.html#module-typing" title="(in Python v3.13)"><code class="xref py py-mod docutils literal notranslate"><span class="pre">typing</span></code></a>, this solution has several downsides:</p> <ul class="simple"> <li>For type checkers, <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#dict" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">dict</span></code></a> is a regular class with two type variables. Allowing <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#dict" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">dict</span></code></a> to be parametrized with a single type argument would require special casing from type checkers, as there is no way to express parametrization overloads. On the other hand, <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.TypedDict" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">TypedDict</span></code></a> is already a <a class="reference external" href="https://typing.python.org/en/latest/spec/glossary.html#term-special-form" title="(in typing)"><span class="xref std std-term">special form</span></a>.</li> <li>If future work extends what inlined typed dictionaries can do, we don’t have to worry about impact of sharing the symbol with <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#dict" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">dict</span></code></a>.</li> <li><a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.Dict" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">typing.Dict</span></code></a> has been deprecated (although not planned for removal) by <a class="pep reference internal" href="../pep-0585/" title="PEP 585 – Type Hinting Generics In Standard Collections">PEP 585</a>. Having it used for a new typing feature would be confusing for users (and would require changes in code linters).</li> </ul> </section> <section id="using-a-simple-dictionary"> <h3><a class="toc-backref" href="#using-a-simple-dictionary" role="doc-backlink">Using a simple dictionary</a></h3> <p>Instead of subscripting the <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.TypedDict" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">TypedDict</span></code></a> class, a plain dictionary could be used as an annotation:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">get_movie</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="p">{</span><span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="nb">str</span><span class="p">}:</span> <span class="o">...</span> </pre></div> </div> <p>However, <a class="pep reference internal" href="../pep-0584/" title="PEP 584 – Add Union Operators To dict">PEP 584</a> added union operators on dictionaries and <a class="pep reference internal" href="../pep-0604/" title="PEP 604 – Allow writing union types as X | Y">PEP 604</a> introduced <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#types-union" title="(in Python v3.13)"><span class="xref std std-ref">union types</span></a>. Both features make use of the <a class="reference external" href="https://docs.python.org/3/reference/expressions.html#bitwise" title="(in Python v3.13)"><span class="xref std std-ref">bitwise or (|)</span></a> operator, making the following use cases incompatible, especially for runtime introspection:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Dictionaries are merged:</span> <span class="k">def</span><span class="w"> </span><span class="nf">fn</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="p">{</span><span class="s1">&#39;a&#39;</span><span class="p">:</span> <span class="nb">int</span><span class="p">}</span> <span class="o">|</span> <span class="p">{</span><span class="s1">&#39;b&#39;</span><span class="p">:</span> <span class="nb">str</span><span class="p">}:</span> <span class="o">...</span> <span class="c1"># Raises a type error at runtime:</span> <span class="k">def</span><span class="w"> </span><span class="nf">fn</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="p">{</span><span class="s1">&#39;a&#39;</span><span class="p">:</span> <span class="nb">int</span><span class="p">}</span> <span class="o">|</span> <span class="nb">int</span><span class="p">:</span> <span class="o">...</span> </pre></div> </div> </section> <section id="extending-other-typed-dictionaries"> <h3><a class="toc-backref" href="#extending-other-typed-dictionaries" role="doc-backlink">Extending other typed dictionaries</a></h3> <p>Several syntaxes could be used to have the ability to extend other typed dictionaries:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">InlinedBase</span> <span class="o">=</span> <span class="n">TypedDict</span><span class="p">[{</span><span class="s1">&#39;a&#39;</span><span class="p">:</span> <span class="nb">int</span><span class="p">}]</span> <span class="n">Inlined</span> <span class="o">=</span> <span class="n">TypedDict</span><span class="p">[</span><span class="n">InlinedBase</span><span class="p">,</span> <span class="p">{</span><span class="s1">&#39;b&#39;</span><span class="p">:</span> <span class="nb">int</span><span class="p">}]</span> <span class="c1"># or, by providing a slice:</span> <span class="n">Inlined</span> <span class="o">=</span> <span class="n">TypedDict</span><span class="p">[{</span><span class="s1">&#39;b&#39;</span><span class="p">:</span> <span class="nb">int</span><span class="p">}</span> <span class="p">:</span> <span class="p">(</span><span class="n">InlinedBase</span><span class="p">,)]</span> </pre></div> </div> <p>As inlined typed dictionaries are meant to only support a subset of the existing syntax, adding this extension mechanism isn’t compelling enough to be supported, considering the added complexity.</p> <p>If intersections were to be added into the type system, it could cover this use case.</p> </section> </section> <section id="open-issues"> <h2><a class="toc-backref" href="#open-issues" role="doc-backlink">Open Issues</a></h2> <section id="should-inlined-typed-dictionaries-be-proper-classes"> <h3><a class="toc-backref" href="#should-inlined-typed-dictionaries-be-proper-classes" role="doc-backlink">Should inlined typed dictionaries be proper classes?</a></h3> <p>The PEP currently defines inlined typed dictionaries as type objects, to be in line with the existing syntaxes. To work around the fact that they don’t have a name, their <a class="reference external" href="https://docs.python.org/3/reference/datamodel.html#type.__name__" title="(in Python v3.13)"><code class="xref py py-attr docutils literal notranslate"><span class="pre">__name__</span></code></a> attribute is set to an empty string.</p> <p>This is somewhat arbitrary, and an alternative name could be used as well (e.g. <code class="docutils literal notranslate"><span class="pre">'&lt;TypedDict&gt;'</span></code>).</p> <p>Alternatively, inlined typed dictionaries could be defined as instances of a new (internal) typing class, e.g. <code class="xref py py-class docutils literal notranslate"><span class="pre">typing._InlinedTypedDict</span></code>. While this solves the naming issue, it requires extra logic in the runtime implementation to provide the introspection attributes (such as <a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.TypedDict.__total__" title="(in Python v3.13)"><code class="xref py py-attr docutils literal notranslate"><span class="pre">__total__</span></code></a>), and tools relying on runtime introspection would have to add proper support for this new type.</p> <p>Depending on the outcome of the runtime implementation, we can more or less easily allow extending inlined typed dictionaries:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">InlinedTD</span> <span class="o">=</span> <span class="n">TypedDict</span><span class="p">[{</span><span class="s1">&#39;a&#39;</span><span class="p">:</span> <span class="nb">int</span><span class="p">}]</span> <span class="c1"># If `InlinedTD` is a typing._InlinedTypedDict instance, this adds complexity:</span> <span class="k">class</span><span class="w"> </span><span class="nc">SubTD</span><span class="p">(</span><span class="n">InlinedTD</span><span class="p">):</span> <span class="k">pass</span> </pre></div> </div> </section> <section id="inlined-typed-dictionaries-and-extra-items"> <h3><a class="toc-backref" href="#inlined-typed-dictionaries-and-extra-items" role="doc-backlink">Inlined typed dictionaries and extra items</a></h3> <p><a class="pep reference internal" href="../pep-0728/" title="PEP 728 – TypedDict with Typed Extra Items">PEP 728</a> introduces the concept of <a class="reference internal" href="../pep-0728/#typed-dict-closed"><span class="std std-ref">closed</span></a> type dictionaries. If this PEP were to be accepted, inlined typed dictionaries will be <em>closed</em> by default. This means <a class="pep reference internal" href="../pep-0728/" title="PEP 728 – TypedDict with Typed Extra Items">PEP 728</a> needs to be addressed first, so that this PEP can be updated accordingly.</p> </section> </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-0764.rst">https://github.com/python/peps/blob/main/peps/pep-0764.rst</a></p> <p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0764.rst">2025-03-04 15:00:34 GMT</a></p> </article> <nav id="pep-sidebar"> <h2>Contents</h2> <ul> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#motivation">Motivation</a></li> <li><a class="reference internal" href="#rationale">Rationale</a></li> <li><a class="reference internal" href="#specification">Specification</a><ul> <li><a class="reference internal" href="#typing-specification-changes">Typing specification changes</a></li> <li><a class="reference internal" href="#id1">Runtime behavior</a></li> </ul> </li> <li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a></li> <li><a class="reference internal" href="#security-implications">Security Implications</a></li> <li><a class="reference internal" href="#how-to-teach-this">How to Teach This</a></li> <li><a class="reference internal" href="#reference-implementation">Reference Implementation</a><ul> <li><a class="reference internal" href="#runtime-implementation">Runtime implementation</a></li> </ul> </li> <li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul> <li><a class="reference internal" href="#using-the-functional-syntax-in-annotations">Using the functional syntax in annotations</a></li> <li><a class="reference internal" href="#using-dict-or-typing-dict-with-a-single-type-argument">Using <code class="docutils literal notranslate"><span class="pre">dict</span></code> or <code class="docutils literal notranslate"><span class="pre">typing.Dict</span></code> with a single type argument</a></li> <li><a class="reference internal" href="#using-a-simple-dictionary">Using a simple dictionary</a></li> <li><a class="reference internal" href="#extending-other-typed-dictionaries">Extending other typed dictionaries</a></li> </ul> </li> <li><a class="reference internal" href="#open-issues">Open Issues</a><ul> <li><a class="reference internal" href="#should-inlined-typed-dictionaries-be-proper-classes">Should inlined typed dictionaries be proper classes?</a></li> <li><a class="reference internal" href="#inlined-typed-dictionaries-and-extra-items">Inlined typed dictionaries and extra items</a></li> </ul> </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-0764.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>

Pages: 1 2 3 4 5 6 7 8 9 10