python-peps/pep-0589/index.html

813 lines
72 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

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

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="color-scheme" content="light dark">
<title>PEP 589 TypedDict: Type Hints for Dictionaries with a Fixed Set of Keys | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-0589/">
<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 589 TypedDict: Type Hints for Dictionaries with a Fixed Set of Keys | peps.python.org'>
<meta property="og:description" content="PEP 484 defines the type Dict[K, V] for uniform dictionaries, where each value has the same type, and arbitrary key values are supported. It doesnt properly support the common pattern where the type of a dictionary value depends on the string value of...">
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-0589/">
<meta property="og:site_name" content="Python Enhancement Proposals (PEPs)">
<meta property="og:image" content="https://peps.python.org/_static/og-image.png">
<meta property="og:image:alt" content="Python PEPs">
<meta property="og:image:width" content="200">
<meta property="og:image:height" content="200">
<meta name="description" content="PEP 484 defines the type Dict[K, V] for uniform dictionaries, where each value has the same type, and arbitrary key values are supported. It doesnt properly support the common pattern where the type of a dictionary value depends on the string value of...">
<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 589</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 589 TypedDict: Type Hints for Dictionaries with a Fixed Set of Keys</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Jukka Lehtosalo &lt;jukka.lehtosalo&#32;&#97;t&#32;iki.fi&gt;</dd>
<dt class="field-even">Sponsor<span class="colon">:</span></dt>
<dd class="field-even">Guido van Rossum &lt;guido&#32;&#97;t&#32;python.org&gt;</dd>
<dt class="field-odd">BDFL-Delegate<span class="colon">:</span></dt>
<dd class="field-odd">Guido van Rossum &lt;guido&#32;&#97;t&#32;python.org&gt;</dd>
<dt class="field-even">Discussions-To<span class="colon">:</span></dt>
<dd class="field-even"><a class="reference external" href="https://mail.python.org/archives/list/typing-sig&#64;python.org/">Typing-SIG list</a></dd>
<dt class="field-odd">Status<span class="colon">:</span></dt>
<dd class="field-odd"><abbr title="Accepted and implementation complete, or no longer active">Final</abbr></dd>
<dt class="field-even">Type<span class="colon">:</span></dt>
<dd class="field-even"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd>
<dt class="field-odd">Topic<span class="colon">:</span></dt>
<dd class="field-odd"><a class="reference external" href="../topic/typing/">Typing</a></dd>
<dt class="field-even">Created<span class="colon">:</span></dt>
<dd class="field-even">20-Mar-2019</dd>
<dt class="field-odd">Python-Version<span class="colon">:</span></dt>
<dd class="field-odd">3.8</dd>
<dt class="field-even">Post-History<span class="colon">:</span></dt>
<dd class="field-even"><p></p></dd>
<dt class="field-odd">Resolution<span class="colon">:</span></dt>
<dd class="field-odd"><a class="reference external" href="https://mail.python.org/archives/list/typing-sig&#64;python.org/message/FDO4KFYWYQEP3U2HVVBEBR3SXPHQSHYR/">Typing-SIG message</a></dd>
</dl>
<hr class="docutils" />
<section id="contents">
<details><summary>Table of Contents</summary><ul class="simple">
<li><a class="reference internal" href="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#motivation">Motivation</a></li>
<li><a class="reference internal" href="#specification">Specification</a><ul>
<li><a class="reference internal" href="#class-based-syntax">Class-based Syntax</a></li>
<li><a class="reference internal" href="#using-typeddict-types">Using TypedDict Types</a></li>
<li><a class="reference internal" href="#inheritance">Inheritance</a></li>
<li><a class="reference internal" href="#totality">Totality</a></li>
<li><a class="reference internal" href="#alternative-syntax">Alternative Syntax</a></li>
<li><a class="reference internal" href="#type-consistency">Type Consistency</a></li>
<li><a class="reference internal" href="#supported-and-unsupported-operations">Supported and Unsupported Operations</a></li>
<li><a class="reference internal" href="#use-of-final-values-and-literal-types">Use of Final Values and Literal Types</a></li>
</ul>
</li>
<li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a></li>
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li>
<li><a class="reference internal" href="#rejected-alternatives">Rejected Alternatives</a></li>
<li><a class="reference internal" href="#acknowledgements">Acknowledgements</a></li>
<li><a class="reference internal" href="#references">References</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
</details></section>
<div class="pep-banner canonical-typing-spec sticky-banner admonition attention">
<p class="admonition-title">Attention</p>
<p>This PEP is a historical document: see <a class="reference external" href="https://typing.readthedocs.io/en/latest/spec/typeddict.html#typeddict" title="(in typing)"><span>TypedDict</span></a> and
<a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.TypedDict" title="(in Python v3.12)"><code class="xref py py-class docutils literal notranslate"><span class="pre">typing.TypedDict</span></code></a> for up-to-date specs and documentation. Canonical typing specs are maintained at the <a class="reference external" href="https://typing.readthedocs.io/en/latest/spec/">typing specs site</a>; runtime typing behaviour is described in the CPython documentation.</p>
<p class="close-button">×</p>
<p>See the <a class="reference external" href="https://typing.readthedocs.io/en/latest/spec/meta.html">typing specification update process</a> for how to propose changes to the typing spec.</p>
</div>
<section id="abstract">
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
<p><a class="pep reference internal" href="../pep-0484/" title="PEP 484 Type Hints">PEP 484</a> defines the type <code class="docutils literal notranslate"><span class="pre">Dict[K,</span> <span class="pre">V]</span></code> for uniform
dictionaries, where each value has the same type, and arbitrary key
values are supported. It doesnt properly support the common pattern
where the type of a dictionary value depends on the string value of
the key. This PEP proposes a type constructor <code class="docutils literal notranslate"><span class="pre">typing.TypedDict</span></code> to
support the use case where a dictionary object has a specific set of
string keys, each with a value of a specific type.</p>
<p>Here is an example where <a class="pep reference internal" href="../pep-0484/" title="PEP 484 Type Hints">PEP 484</a> doesnt allow us to annotate
satisfactorily:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">movie</span> <span class="o">=</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>
</pre></div>
</div>
<p>This PEP proposes the addition of a new type constructor, called
<code class="docutils literal notranslate"><span class="pre">TypedDict</span></code>, to allow the type of <code class="docutils literal notranslate"><span class="pre">movie</span></code> to be represented
precisely:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TypedDict</span>
<span class="k">class</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>
</pre></div>
</div>
<p>Now a type checker should accept this code:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">movie</span><span class="p">:</span> <span class="n">Movie</span> <span class="o">=</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>
</pre></div>
</div>
</section>
<section id="motivation">
<h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2>
<p>Representing an object or structured data using (potentially nested)
dictionaries with string keys (instead of a user-defined class) is a
common pattern in Python programs. Representing JSON objects is
perhaps the canonical use case, and this is popular enough that Python
ships with a JSON library. This PEP proposes a way to allow such code
to be type checked more effectively.</p>
<p>More generally, representing pure data objects using only Python
primitive types such as dictionaries, strings and lists has had
certain appeal. They are easy to serialize and deserialize even
when not using JSON. They trivially support various useful operations
with no extra effort, including pretty-printing (through <code class="docutils literal notranslate"><span class="pre">str()</span></code> and
the <code class="docutils literal notranslate"><span class="pre">pprint</span></code> module), iteration, and equality comparisons.</p>
<p><a class="pep reference internal" href="../pep-0484/" title="PEP 484 Type Hints">PEP 484</a> doesnt properly support the use cases mentioned above. Lets
consider a dictionary object that has exactly two valid string keys,
<code class="docutils literal notranslate"><span class="pre">'name'</span></code> with value type <code class="docutils literal notranslate"><span class="pre">str</span></code>, and <code class="docutils literal notranslate"><span class="pre">'year'</span></code> with value type
<code class="docutils literal notranslate"><span class="pre">int</span></code>. The <a class="pep reference internal" href="../pep-0484/" title="PEP 484 Type Hints">PEP 484</a> type <code class="docutils literal notranslate"><span class="pre">Dict[str,</span> <span class="pre">Any]</span></code> would be suitable, but
it is too lenient, as arbitrary string keys can be used, and arbitrary
values are valid. Similarly, <code class="docutils literal notranslate"><span class="pre">Dict[str,</span> <span class="pre">Union[str,</span> <span class="pre">int]]</span></code> is too
general, as the value for key <code class="docutils literal notranslate"><span class="pre">'name'</span></code> could be an <code class="docutils literal notranslate"><span class="pre">int</span></code>, and
arbitrary string keys are allowed. Also, the type of a subscription
expression such as <code class="docutils literal notranslate"><span class="pre">d['name']</span></code> (assuming <code class="docutils literal notranslate"><span class="pre">d</span></code> to be a dictionary of
this type) would be <code class="docutils literal notranslate"><span class="pre">Union[str,</span> <span class="pre">int]</span></code>, which is too wide.</p>
<p>Dataclasses are a more recent alternative to solve this use case, but
there is still a lot of existing code that was written before
dataclasses became available, especially in large existing codebases
where type hinting and checking has proven to be helpful. Unlike
dictionary objects, dataclasses dont directly support JSON
serialization, though there is a third-party package that implements
it <a class="footnote-reference brackets" href="#dataclasses-json" id="id1">[1]</a>.</p>
</section>
<section id="specification">
<h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2>
<p>A TypedDict type represents dictionary objects with a specific set of
string keys, and with specific value types for each valid key. Each
string key can be either required (it must be present) or
non-required (it doesnt need to exist).</p>
<p>This PEP proposes two ways of defining TypedDict types. The first uses
a class-based syntax. The second is an alternative
assignment-based syntax that is provided for backwards compatibility,
to allow the feature to be backported to older Python versions. The
rationale is similar to why <a class="pep reference internal" href="../pep-0484/" title="PEP 484 Type Hints">PEP 484</a> supports a comment-based
annotation syntax for Python 2.7: type hinting is particularly useful
for large existing codebases, and these often need to run on older
Python versions. The two syntax options parallel the syntax variants
supported by <code class="docutils literal notranslate"><span class="pre">typing.NamedTuple</span></code>. Other proposed features include
TypedDict inheritance and totality (specifying whether keys are
required or not).</p>
<p>This PEP also provides a sketch of how a type checker is expected
to support type checking operations involving TypedDict objects.
Similar to <a class="pep reference internal" href="../pep-0484/" title="PEP 484 Type Hints">PEP 484</a>, this discussion is left somewhat vague on purpose,
to allow experimentation with a wide variety of different type
checking approaches. In particular, type compatibility should be
based on structural compatibility: a more specific TypedDict type can
be compatible with a smaller (more general) TypedDict type.</p>
<section id="class-based-syntax">
<h3><a class="toc-backref" href="#class-based-syntax" role="doc-backlink">Class-based Syntax</a></h3>
<p>A TypedDict type can be defined using the class definition syntax with
<code class="docutils literal notranslate"><span class="pre">typing.TypedDict</span></code> as the sole base class:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TypedDict</span>
<span class="k">class</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>
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">Movie</span></code> is a TypedDict type with two items: <code class="docutils literal notranslate"><span class="pre">'name'</span></code> (with type
<code class="docutils literal notranslate"><span class="pre">str</span></code>) and <code class="docutils literal notranslate"><span class="pre">'year'</span></code> (with type <code class="docutils literal notranslate"><span class="pre">int</span></code>).</p>
<p>A type checker should validate that the body of a class-based
TypedDict definition conforms to the following rules:</p>
<ul class="simple">
<li>The class body should only contain lines with item definitions of the
form <code class="docutils literal notranslate"><span class="pre">key:</span> <span class="pre">value_type</span></code>, optionally preceded by a docstring. The
syntax for item definitions is identical to attribute annotations,
but there must be no initializer, and the key name actually refers
to the string value of the key instead of an attribute name.</li>
<li>Type comments cannot be used with the class-based syntax, for
consistency with the class-based <code class="docutils literal notranslate"><span class="pre">NamedTuple</span></code> syntax. (Note that
it would not be sufficient to support type comments for backwards
compatibility with Python 2.7, since the class definition may have a
<code class="docutils literal notranslate"><span class="pre">total</span></code> keyword argument, as discussed below, and this isnt valid
syntax in Python 2.7.) Instead, this PEP provides an alternative,
assignment-based syntax for backwards compatibility, discussed in
<a class="reference internal" href="#alternative-syntax">Alternative Syntax</a>.</li>
<li>String literal forward references are valid in the value types.</li>
<li>Methods are not allowed, since the runtime type of a TypedDict
object will always be just <code class="docutils literal notranslate"><span class="pre">dict</span></code> (it is never a subclass of
<code class="docutils literal notranslate"><span class="pre">dict</span></code>).</li>
<li>Specifying a metaclass is not allowed.</li>
</ul>
<p>An empty TypedDict can be created by only including <code class="docutils literal notranslate"><span class="pre">pass</span></code> in the
body (if there is a docstring, <code class="docutils literal notranslate"><span class="pre">pass</span></code> can be omitted):</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">EmptyDict</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span>
<span class="k">pass</span>
</pre></div>
</div>
</section>
<section id="using-typeddict-types">
<h3><a class="toc-backref" href="#using-typeddict-types" role="doc-backlink">Using TypedDict Types</a></h3>
<p>Here is an example of how the type <code class="docutils literal notranslate"><span class="pre">Movie</span></code> can be used:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">movie</span><span class="p">:</span> <span class="n">Movie</span> <span class="o">=</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>
</pre></div>
</div>
<p>An explicit <code class="docutils literal notranslate"><span class="pre">Movie</span></code> type annotation is generally needed, as
otherwise an ordinary dictionary type could be assumed by a type
checker, for backwards compatibility. When a type checker can infer
that a constructed dictionary object should be a TypedDict, an
explicit annotation can be omitted. A typical example is a dictionary
object as a function argument. In this example, a type checker is
expected to infer that the dictionary argument should be understood as
a TypedDict:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">record_movie</span><span class="p">(</span><span class="n">movie</span><span class="p">:</span> <span class="n">Movie</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span> <span class="o">...</span>
<span class="n">record_movie</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>
</pre></div>
</div>
<p>Another example where a type checker should treat a dictionary display
as a TypedDict is in an assignment to a variable with a previously
declared TypedDict type:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">movie</span><span class="p">:</span> <span class="n">Movie</span>
<span class="o">...</span>
<span class="n">movie</span> <span class="o">=</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>
</pre></div>
</div>
<p>Operations on <code class="docutils literal notranslate"><span class="pre">movie</span></code> can be checked by a static type checker:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">movie</span><span class="p">[</span><span class="s1">&#39;director&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;Ridley Scott&#39;</span> <span class="c1"># Error: invalid key &#39;director&#39;</span>
<span class="n">movie</span><span class="p">[</span><span class="s1">&#39;year&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;1982&#39;</span> <span class="c1"># Error: invalid value type (&quot;int&quot; expected)</span>
</pre></div>
</div>
<p>The code below should be rejected, since <code class="docutils literal notranslate"><span class="pre">'title'</span></code> is not a valid
key, and the <code class="docutils literal notranslate"><span class="pre">'name'</span></code> key is missing:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">movie2</span><span class="p">:</span> <span class="n">Movie</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;title&#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>
</pre></div>
</div>
<p>The created TypedDict type object is not a real class object. Here
are the only uses of the type a type checker is expected to allow:</p>
<ul>
<li>It can be used in type annotations and in any context where an
arbitrary type hint is valid, such as in type aliases and as the
target type of a cast.</li>
<li>It can be used as a callable object with keyword arguments
corresponding to the TypedDict items. Non-keyword arguments are not
allowed. Example:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">m</span> <span class="o">=</span> <span class="n">Movie</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Blade Runner&#39;</span><span class="p">,</span> <span class="n">year</span><span class="o">=</span><span class="mi">1982</span><span class="p">)</span>
</pre></div>
</div>
<p>When called, the TypedDict type object returns an ordinary
dictionary object at runtime:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nb">print</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="n">m</span><span class="p">))</span> <span class="c1"># &lt;class &#39;dict&#39;&gt;</span>
</pre></div>
</div>
</li>
<li>It can be used as a base class, but only when defining a derived
TypedDict. This is discussed in more detail below.</li>
</ul>
<p>In particular, TypedDict type objects cannot be used in
<code class="docutils literal notranslate"><span class="pre">isinstance()</span></code> tests such as <code class="docutils literal notranslate"><span class="pre">isinstance(d,</span> <span class="pre">Movie)</span></code>. The reason is
that there is no existing support for checking types of dictionary
item values, since <code class="docutils literal notranslate"><span class="pre">isinstance()</span></code> does not work with many <a class="pep reference internal" href="../pep-0484/" title="PEP 484 Type Hints">PEP 484</a>
types, including common ones like <code class="docutils literal notranslate"><span class="pre">List[str]</span></code>. This would be needed
for cases like this:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Strings</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span>
<span class="n">items</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span>
<span class="nb">print</span><span class="p">(</span><span class="nb">isinstance</span><span class="p">({</span><span class="s1">&#39;items&#39;</span><span class="p">:</span> <span class="p">[</span><span class="mi">1</span><span class="p">]},</span> <span class="n">Strings</span><span class="p">))</span> <span class="c1"># Should be False</span>
<span class="nb">print</span><span class="p">(</span><span class="nb">isinstance</span><span class="p">({</span><span class="s1">&#39;items&#39;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;x&#39;</span><span class="p">]},</span> <span class="n">Strings</span><span class="p">))</span> <span class="c1"># Should be True</span>
</pre></div>
</div>
<p>The above use case is not supported. This is consistent with how
<code class="docutils literal notranslate"><span class="pre">isinstance()</span></code> is not supported for <code class="docutils literal notranslate"><span class="pre">List[str]</span></code>.</p>
</section>
<section id="inheritance">
<h3><a class="toc-backref" href="#inheritance" role="doc-backlink">Inheritance</a></h3>
<p>It is possible for a TypedDict type to inherit from one or more
TypedDict types using the class-based syntax. In this case the
<code class="docutils literal notranslate"><span class="pre">TypedDict</span></code> base class should not be included. Example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">BookBasedMovie</span><span class="p">(</span><span class="n">Movie</span><span class="p">):</span>
<span class="n">based_on</span><span class="p">:</span> <span class="nb">str</span>
</pre></div>
</div>
<p>Now <code class="docutils literal notranslate"><span class="pre">BookBasedMovie</span></code> has keys <code class="docutils literal notranslate"><span class="pre">name</span></code>, <code class="docutils literal notranslate"><span class="pre">year</span></code>, and <code class="docutils literal notranslate"><span class="pre">based_on</span></code>.
It is equivalent to this definition, since TypedDict types use
structural compatibility:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">BookBasedMovie</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">based_on</span><span class="p">:</span> <span class="nb">str</span>
</pre></div>
</div>
<p>Here is an example of multiple inheritance:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">X</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span>
<span class="n">x</span><span class="p">:</span> <span class="nb">int</span>
<span class="k">class</span> <span class="nc">Y</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span>
<span class="n">y</span><span class="p">:</span> <span class="nb">str</span>
<span class="k">class</span> <span class="nc">XYZ</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">):</span>
<span class="n">z</span><span class="p">:</span> <span class="nb">bool</span>
</pre></div>
</div>
<p>The TypedDict <code class="docutils literal notranslate"><span class="pre">XYZ</span></code> has three items: <code class="docutils literal notranslate"><span class="pre">x</span></code> (type <code class="docutils literal notranslate"><span class="pre">int</span></code>), <code class="docutils literal notranslate"><span class="pre">y</span></code>
(type <code class="docutils literal notranslate"><span class="pre">str</span></code>), and <code class="docutils literal notranslate"><span class="pre">z</span></code> (type <code class="docutils literal notranslate"><span class="pre">bool</span></code>).</p>
<p>A TypedDict cannot inherit from both a TypedDict type and a
non-TypedDict base class.</p>
<p>Additional notes on TypedDict class inheritance:</p>
<ul>
<li>Changing a field type of a parent TypedDict class in a subclass is not allowed.
Example:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">X</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span>
<span class="n">x</span><span class="p">:</span> <span class="nb">str</span>
<span class="k">class</span> <span class="nc">Y</span><span class="p">(</span><span class="n">X</span><span class="p">):</span>
<span class="n">x</span><span class="p">:</span> <span class="nb">int</span> <span class="c1"># Type check error: cannot overwrite TypedDict field &quot;x&quot;</span>
</pre></div>
</div>
<p>In the example outlined above TypedDict class annotations returns
type <code class="docutils literal notranslate"><span class="pre">str</span></code> for key <code class="docutils literal notranslate"><span class="pre">x</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nb">print</span><span class="p">(</span><span class="n">Y</span><span class="o">.</span><span class="vm">__annotations__</span><span class="p">)</span> <span class="c1"># {&#39;x&#39;: &lt;class &#39;str&#39;&gt;}</span>
</pre></div>
</div>
</li>
<li>Multiple inheritance does not allow conflict types for the same name field:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">X</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span>
<span class="n">x</span><span class="p">:</span> <span class="nb">int</span>
<span class="k">class</span> <span class="nc">Y</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span>
<span class="n">x</span><span class="p">:</span> <span class="nb">str</span>
<span class="k">class</span> <span class="nc">XYZ</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">):</span> <span class="c1"># Type check error: cannot overwrite TypedDict field &quot;x&quot; while merging</span>
<span class="n">xyz</span><span class="p">:</span> <span class="nb">bool</span>
</pre></div>
</div>
</li>
</ul>
</section>
<section id="totality">
<h3><a class="toc-backref" href="#totality" role="doc-backlink">Totality</a></h3>
<p>By default, all keys must be present in a TypedDict. It is possible
to override this by specifying <em>totality</em>. Here is how to do this
using the class-based syntax:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Movie</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">,</span> <span class="n">total</span><span class="o">=</span><span class="kc">False</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>
</pre></div>
</div>
<p>This means that a <code class="docutils literal notranslate"><span class="pre">Movie</span></code> TypedDict can have any of the keys omitted. Thus
these are valid:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">m</span><span class="p">:</span> <span class="n">Movie</span> <span class="o">=</span> <span class="p">{}</span>
<span class="n">m2</span><span class="p">:</span> <span class="n">Movie</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;year&#39;</span><span class="p">:</span> <span class="mi">2015</span><span class="p">}</span>
</pre></div>
</div>
<p>A type checker is only expected to support a literal <code class="docutils literal notranslate"><span class="pre">False</span></code> or
<code class="docutils literal notranslate"><span class="pre">True</span></code> as the value of the <code class="docutils literal notranslate"><span class="pre">total</span></code> argument. <code class="docutils literal notranslate"><span class="pre">True</span></code> is the
default, and makes all items defined in the class body be required.</p>
<p>The totality flag only applies to items defined in the body of the
TypedDict definition. Inherited items wont be affected, and instead
use totality of the TypedDict type where they were defined. This makes
it possible to have a combination of required and non-required keys in
a single TypedDict type.</p>
</section>
<section id="alternative-syntax">
<h3><a class="toc-backref" href="#alternative-syntax" role="doc-backlink">Alternative Syntax</a></h3>
<p>This PEP also proposes an alternative syntax that can be backported to
older Python versions such as 3.5 and 2.7 that dont support the
variable definition syntax introduced in <a class="pep reference internal" href="../pep-0526/" title="PEP 526 Syntax for Variable Annotations">PEP 526</a>. It
resembles the traditional syntax for defining named tuples:</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;Movie&#39;</span><span class="p">,</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>
</pre></div>
</div>
<p>It is also possible to specify totality using the alternative syntax:</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;Movie&#39;</span><span class="p">,</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="n">total</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</pre></div>
</div>
<p>The semantics are equivalent to the class-based syntax. This syntax
doesnt support inheritance, however, and there is no way to
have both required and non-required fields in a single type. The
motivation for this is keeping the backwards compatible syntax as
simple as possible while covering the most common use cases.</p>
<p>A type checker is only expected to accept a dictionary display expression
as the second argument to <code class="docutils literal notranslate"><span class="pre">TypedDict</span></code>. In particular, a variable that
refers to a dictionary object does not need to be supported, to simplify
implementation.</p>
</section>
<section id="type-consistency">
<h3><a class="toc-backref" href="#type-consistency" role="doc-backlink">Type Consistency</a></h3>
<p>Informally speaking, <em>type consistency</em> is a generalization of the
is-subtype-of relation to support the <code class="docutils literal notranslate"><span class="pre">Any</span></code> type. It is defined
more formally in <a class="pep reference internal" href="../pep-0483/" title="PEP 483 The Theory of Type Hints">PEP 483</a>. This section introduces the
new, non-trivial rules needed to support type consistency for
TypedDict types.</p>
<p>First, any TypedDict type is consistent with <code class="docutils literal notranslate"><span class="pre">Mapping[str,</span> <span class="pre">object]</span></code>.
Second, a TypedDict type <code class="docutils literal notranslate"><span class="pre">A</span></code> is consistent with TypedDict <code class="docutils literal notranslate"><span class="pre">B</span></code> if
<code class="docutils literal notranslate"><span class="pre">A</span></code> is structurally compatible with <code class="docutils literal notranslate"><span class="pre">B</span></code>. This is true if and only
if both of these conditions are satisfied:</p>
<ul class="simple">
<li>For each key in <code class="docutils literal notranslate"><span class="pre">B</span></code>, <code class="docutils literal notranslate"><span class="pre">A</span></code> has the corresponding key and the
corresponding value type in <code class="docutils literal notranslate"><span class="pre">A</span></code> is consistent with the value type
in <code class="docutils literal notranslate"><span class="pre">B</span></code>. For each key in <code class="docutils literal notranslate"><span class="pre">B</span></code>, the value type in <code class="docutils literal notranslate"><span class="pre">B</span></code> is also
consistent with the corresponding value type in <code class="docutils literal notranslate"><span class="pre">A</span></code>.</li>
<li>For each required key in <code class="docutils literal notranslate"><span class="pre">B</span></code>, the corresponding key is required
in <code class="docutils literal notranslate"><span class="pre">A</span></code>. For each non-required key in <code class="docutils literal notranslate"><span class="pre">B</span></code>, the corresponding key
is not required in <code class="docutils literal notranslate"><span class="pre">A</span></code>.</li>
</ul>
<p>Discussion:</p>
<ul>
<li>Value types behave invariantly, since TypedDict objects are mutable.
This is similar to mutable container types such as <code class="docutils literal notranslate"><span class="pre">List</span></code> and
<code class="docutils literal notranslate"><span class="pre">Dict</span></code>. Example where this is relevant:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">A</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span>
<span class="n">x</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">int</span><span class="p">]</span>
<span class="k">class</span> <span class="nc">B</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span>
<span class="n">x</span><span class="p">:</span> <span class="nb">int</span>
<span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="n">A</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">a</span><span class="p">[</span><span class="s1">&#39;x&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">b</span><span class="p">:</span> <span class="n">B</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;x&#39;</span><span class="p">:</span> <span class="mi">0</span><span class="p">}</span>
<span class="n">f</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> <span class="c1"># Type check error: &#39;B&#39; not compatible with &#39;A&#39;</span>
<span class="n">b</span><span class="p">[</span><span class="s1">&#39;x&#39;</span><span class="p">]</span> <span class="o">+</span> <span class="mi">1</span> <span class="c1"># Runtime error: None + 1</span>
</pre></div>
</div>
</li>
<li>A TypedDict type with a required key is not consistent with a
TypedDict type where the same key is a non-required key, since the
latter allows keys to be deleted. Example where this is relevant:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">A</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">,</span> <span class="n">total</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
<span class="n">x</span><span class="p">:</span> <span class="nb">int</span>
<span class="k">class</span> <span class="nc">B</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span>
<span class="n">x</span><span class="p">:</span> <span class="nb">int</span>
<span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="n">A</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">del</span> <span class="n">a</span><span class="p">[</span><span class="s1">&#39;x&#39;</span><span class="p">]</span>
<span class="n">b</span><span class="p">:</span> <span class="n">B</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;x&#39;</span><span class="p">:</span> <span class="mi">0</span><span class="p">}</span>
<span class="n">f</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> <span class="c1"># Type check error: &#39;B&#39; not compatible with &#39;A&#39;</span>
<span class="n">b</span><span class="p">[</span><span class="s1">&#39;x&#39;</span><span class="p">]</span> <span class="o">+</span> <span class="mi">1</span> <span class="c1"># Runtime KeyError: &#39;x&#39;</span>
</pre></div>
</div>
</li>
<li>A TypedDict type <code class="docutils literal notranslate"><span class="pre">A</span></code> with no key <code class="docutils literal notranslate"><span class="pre">'x'</span></code> is not consistent with a
TypedDict type with a non-required key <code class="docutils literal notranslate"><span class="pre">'x'</span></code>, since at runtime
the key <code class="docutils literal notranslate"><span class="pre">'x'</span></code> could be present and have an incompatible type
(which may not be visible through <code class="docutils literal notranslate"><span class="pre">A</span></code> due to structural subtyping).
Example:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">A</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">,</span> <span class="n">total</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
<span class="n">x</span><span class="p">:</span> <span class="nb">int</span>
<span class="n">y</span><span class="p">:</span> <span class="nb">int</span>
<span class="k">class</span> <span class="nc">B</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">,</span> <span class="n">total</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
<span class="n">x</span><span class="p">:</span> <span class="nb">int</span>
<span class="k">class</span> <span class="nc">C</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">,</span> <span class="n">total</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
<span class="n">x</span><span class="p">:</span> <span class="nb">int</span>
<span class="n">y</span><span class="p">:</span> <span class="nb">str</span>
<span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="n">A</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">a</span><span class="p">[</span><span class="s1">&#39;y&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
<span class="k">def</span> <span class="nf">g</span><span class="p">(</span><span class="n">b</span><span class="p">:</span> <span class="n">B</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">f</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> <span class="c1"># Type check error: &#39;B&#39; incompatible with &#39;A&#39;</span>
<span class="n">c</span><span class="p">:</span> <span class="n">C</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;x&#39;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="s1">&#39;y&#39;</span><span class="p">:</span> <span class="s1">&#39;foo&#39;</span><span class="p">}</span>
<span class="n">g</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>
<span class="n">c</span><span class="p">[</span><span class="s1">&#39;y&#39;</span><span class="p">]</span> <span class="o">+</span> <span class="s1">&#39;bar&#39;</span> <span class="c1"># Runtime error: int + str</span>
</pre></div>
</div>
</li>
<li>A TypedDict isnt consistent with any <code class="docutils literal notranslate"><span class="pre">Dict[...]</span></code> type, since
dictionary types allow destructive operations, including
<code class="docutils literal notranslate"><span class="pre">clear()</span></code>. They also allow arbitrary keys to be set, which
would compromise type safety. Example:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">A</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span>
<span class="n">x</span><span class="p">:</span> <span class="nb">int</span>
<span class="k">class</span> <span class="nc">B</span><span class="p">(</span><span class="n">A</span><span class="p">):</span>
<span class="n">y</span><span class="p">:</span> <span class="nb">str</span>
<span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="n">d</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">int</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">d</span><span class="p">[</span><span class="s1">&#39;y&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">def</span> <span class="nf">g</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="n">A</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">f</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="c1"># Type check error: &#39;A&#39; incompatible with Dict[str, int]</span>
<span class="n">b</span><span class="p">:</span> <span class="n">B</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;x&#39;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="s1">&#39;y&#39;</span><span class="p">:</span> <span class="s1">&#39;foo&#39;</span><span class="p">}</span>
<span class="n">g</span><span class="p">(</span><span class="n">b</span><span class="p">)</span>
<span class="n">b</span><span class="p">[</span><span class="s1">&#39;y&#39;</span><span class="p">]</span> <span class="o">+</span> <span class="s1">&#39;bar&#39;</span> <span class="c1"># Runtime error: int + str</span>
</pre></div>
</div>
</li>
<li>A TypedDict with all <code class="docutils literal notranslate"><span class="pre">int</span></code> values is not consistent with
<code class="docutils literal notranslate"><span class="pre">Mapping[str,</span> <span class="pre">int]</span></code>, since there may be additional non-<code class="docutils literal notranslate"><span class="pre">int</span></code>
values not visible through the type, due to structural subtyping.
These can be accessed using the <code class="docutils literal notranslate"><span class="pre">values()</span></code> and <code class="docutils literal notranslate"><span class="pre">items()</span></code>
methods in <code class="docutils literal notranslate"><span class="pre">Mapping</span></code>, for example. Example:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">A</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span>
<span class="n">x</span><span class="p">:</span> <span class="nb">int</span>
<span class="k">class</span> <span class="nc">B</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span>
<span class="n">x</span><span class="p">:</span> <span class="nb">int</span>
<span class="n">y</span><span class="p">:</span> <span class="nb">str</span>
<span class="k">def</span> <span class="nf">sum_values</span><span class="p">(</span><span class="n">m</span><span class="p">:</span> <span class="n">Mapping</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">int</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="n">n</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">m</span><span class="o">.</span><span class="n">values</span><span class="p">():</span>
<span class="n">n</span> <span class="o">+=</span> <span class="n">v</span> <span class="c1"># Runtime error</span>
<span class="k">return</span> <span class="n">n</span>
<span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="n">A</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">sum_values</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="c1"># Error: &#39;A&#39; incompatible with Mapping[str, int]</span>
<span class="n">b</span><span class="p">:</span> <span class="n">B</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;x&#39;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="s1">&#39;y&#39;</span><span class="p">:</span> <span class="s1">&#39;foo&#39;</span><span class="p">}</span>
<span class="n">f</span><span class="p">(</span><span class="n">b</span><span class="p">)</span>
</pre></div>
</div>
</li>
</ul>
</section>
<section id="supported-and-unsupported-operations">
<h3><a class="toc-backref" href="#supported-and-unsupported-operations" role="doc-backlink">Supported and Unsupported Operations</a></h3>
<p>Type checkers should support restricted forms of most <code class="docutils literal notranslate"><span class="pre">dict</span></code>
operations on TypedDict objects. The guiding principle is that
operations not involving <code class="docutils literal notranslate"><span class="pre">Any</span></code> types should be rejected by type
checkers if they may violate runtime type safety. Here are some of
the most important type safety violations to prevent:</p>
<ol class="arabic simple">
<li>A required key is missing.</li>
<li>A value has an invalid type.</li>
<li>A key that is not defined in the TypedDict type is added.</li>
</ol>
<p>A key that is not a literal should generally be rejected, since its
value is unknown during type checking, and thus can cause some of the
above violations. (<a class="reference internal" href="#use-of-final-values-and-literal-types">Use of Final Values and Literal Types</a>
generalizes this to cover final names and literal types.)</p>
<p>The use of a key that is not known to exist should be reported as an
error, even if this wouldnt necessarily generate a runtime type
error. These are often mistakes, and these may insert values with an
invalid type if structural subtyping hides the types of certain items.
For example, <code class="docutils literal notranslate"><span class="pre">d['x']</span> <span class="pre">=</span> <span class="pre">1</span></code> should generate a type check error if
<code class="docutils literal notranslate"><span class="pre">'x'</span></code> is not a valid key for <code class="docutils literal notranslate"><span class="pre">d</span></code> (which is assumed to be a
TypedDict type).</p>
<p>Extra keys included in TypedDict object construction should also be
caught. In this example, the <code class="docutils literal notranslate"><span class="pre">director</span></code> key is not defined in
<code class="docutils literal notranslate"><span class="pre">Movie</span></code> and is expected to generate an error from a type checker:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">m</span><span class="p">:</span> <span class="n">Movie</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span>
<span class="n">name</span><span class="o">=</span><span class="s1">&#39;Alien&#39;</span><span class="p">,</span>
<span class="n">year</span><span class="o">=</span><span class="mi">1979</span><span class="p">,</span>
<span class="n">director</span><span class="o">=</span><span class="s1">&#39;Ridley Scott&#39;</span><span class="p">)</span> <span class="c1"># error: Unexpected key &#39;director&#39;</span>
</pre></div>
</div>
<p>Type checkers should reject the following operations on TypedDict
objects as unsafe, even though they are valid for normal dictionaries:</p>
<ul class="simple">
<li>Operations with arbitrary <code class="docutils literal notranslate"><span class="pre">str</span></code> keys (instead of string literals
or other expressions with known string values) should generally be
rejected. This involves both destructive operations such as setting
an item and read-only operations such as subscription expressions.
As an exception to the above rule, <code class="docutils literal notranslate"><span class="pre">d.get(e)</span></code> and <code class="docutils literal notranslate"><span class="pre">e</span> <span class="pre">in</span> <span class="pre">d</span></code>
should be allowed for TypedDict objects, for an arbitrary expression
<code class="docutils literal notranslate"><span class="pre">e</span></code> with type <code class="docutils literal notranslate"><span class="pre">str</span></code>. The motivation is that these are safe and
can be useful for introspecting TypedDict objects. The static type
of <code class="docutils literal notranslate"><span class="pre">d.get(e)</span></code> should be <code class="docutils literal notranslate"><span class="pre">object</span></code> if the string value of <code class="docutils literal notranslate"><span class="pre">e</span></code>
cannot be determined statically.</li>
<li><code class="docutils literal notranslate"><span class="pre">clear()</span></code> is not safe since it could remove required keys, some of
which may not be directly visible because of structural
subtyping. <code class="docutils literal notranslate"><span class="pre">popitem()</span></code> is similarly unsafe, even if all known
keys are not required (<code class="docutils literal notranslate"><span class="pre">total=False</span></code>).</li>
<li><code class="docutils literal notranslate"><span class="pre">del</span> <span class="pre">obj['key']</span></code> should be rejected unless <code class="docutils literal notranslate"><span class="pre">'key'</span></code> is a
non-required key.</li>
</ul>
<p>Type checkers may allow reading an item using <code class="docutils literal notranslate"><span class="pre">d['x']</span></code> even if
the key <code class="docutils literal notranslate"><span class="pre">'x'</span></code> is not required, instead of requiring the use of
<code class="docutils literal notranslate"><span class="pre">d.get('x')</span></code> or an explicit <code class="docutils literal notranslate"><span class="pre">'x'</span> <span class="pre">in</span> <span class="pre">d</span></code> check. The rationale is
that tracking the existence of keys is difficult to implement in full
generality, and that disallowing this could require many changes to
existing code.</p>
<p>The exact type checking rules are up to each type checker to decide.
In some cases potentially unsafe operations may be accepted if the
alternative is to generate false positive errors for idiomatic code.</p>
</section>
<section id="use-of-final-values-and-literal-types">
<h3><a class="toc-backref" href="#use-of-final-values-and-literal-types" role="doc-backlink">Use of Final Values and Literal Types</a></h3>
<p>Type checkers should allow final names (<a class="pep reference internal" href="../pep-0591/" title="PEP 591 Adding a final qualifier to typing">PEP 591</a>) with
string values to be used instead of string literals in operations on
TypedDict objects. For example, this is valid:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">YEAR</span><span class="p">:</span> <span class="n">Final</span> <span class="o">=</span> <span class="s1">&#39;year&#39;</span>
<span class="n">m</span><span class="p">:</span> <span class="n">Movie</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="s1">&#39;Alien&#39;</span><span class="p">,</span> <span class="s1">&#39;year&#39;</span><span class="p">:</span> <span class="mi">1979</span><span class="p">}</span>
<span class="n">years_since_epoch</span> <span class="o">=</span> <span class="n">m</span><span class="p">[</span><span class="n">YEAR</span><span class="p">]</span> <span class="o">-</span> <span class="mi">1970</span>
</pre></div>
</div>
<p>Similarly, an expression with a suitable literal type
(<a class="pep reference internal" href="../pep-0586/" title="PEP 586 Literal Types">PEP 586</a>) can be used instead of a literal value:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">get_value</span><span class="p">(</span><span class="n">movie</span><span class="p">:</span> <span class="n">Movie</span><span class="p">,</span>
<span class="n">key</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="s1">&#39;year&#39;</span><span class="p">,</span> <span class="s1">&#39;name&#39;</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">Union</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">str</span><span class="p">]:</span>
<span class="k">return</span> <span class="n">movie</span><span class="p">[</span><span class="n">key</span><span class="p">]</span>
</pre></div>
</div>
<p>Type checkers are only expected to support actual string literals, not
final names or literal types, for specifying keys in a TypedDict type
definition. Also, only a boolean literal can be used to specify
totality in a TypedDict definition. The motivation for this is to
make type declarations self-contained, and to simplify the
implementation of type checkers.</p>
</section>
</section>
<section id="backwards-compatibility">
<h2><a class="toc-backref" href="#backwards-compatibility" role="doc-backlink">Backwards Compatibility</a></h2>
<p>To retain backwards compatibility, type checkers should not infer a
TypedDict type unless it is sufficiently clear that this is desired by
the programmer. When unsure, an ordinary dictionary type should be
inferred. Otherwise existing code that type checks without errors may
start generating errors once TypedDict support is added to the type
checker, since TypedDict types are more restrictive than dictionary
types. In particular, they arent subtypes of dictionary types.</p>
</section>
<section id="reference-implementation">
<h2><a class="toc-backref" href="#reference-implementation" role="doc-backlink">Reference Implementation</a></h2>
<p>The mypy <a class="footnote-reference brackets" href="#mypy" id="id2">[2]</a> type checker supports TypedDict types. A reference
implementation of the runtime component is provided in the
<code class="docutils literal notranslate"><span class="pre">typing_extensions</span></code> <a class="footnote-reference brackets" href="#typing-extensions" id="id3">[3]</a> module. The original
implementation was in the <code class="docutils literal notranslate"><span class="pre">mypy_extensions</span></code> <a class="footnote-reference brackets" href="#mypy-extensions" id="id4">[4]</a>
module.</p>
</section>
<section id="rejected-alternatives">
<h2><a class="toc-backref" href="#rejected-alternatives" role="doc-backlink">Rejected Alternatives</a></h2>
<p>Several proposed ideas were rejected. The current set of features
seem to cover a lot of ground, and it was not clear which of the
proposed extensions would be more than marginally useful. This PEP
defines a baseline feature that can be potentially extended later.</p>
<p>These are rejected on principle, as incompatible with the spirit of
this proposal:</p>
<ul class="simple">
<li>TypedDict isnt extensible, and it addresses only a specific use
case. TypedDict objects are regular dictionaries at runtime, and
TypedDict cannot be used with other dictionary-like or mapping-like
classes, including subclasses of <code class="docutils literal notranslate"><span class="pre">dict</span></code>. There is no way to add
methods to TypedDict types. The motivation here is simplicity.</li>
<li>TypedDict type definitions could plausibly used to perform runtime
type checking of dictionaries. For example, they could be used to
validate that a JSON object conforms to the schema specified by a
TypedDict type. This PEP doesnt include such functionality, since
the focus of this proposal is static type checking only, and other
existing types do not support this, as discussed in <a class="reference internal" href="#class-based-syntax">Class-based
syntax</a>. Such functionality can be provided by a third-party
library using the <code class="docutils literal notranslate"><span class="pre">typing_inspect</span></code> <a class="footnote-reference brackets" href="#typing-inspect" id="id5">[5]</a> third-party
module, for example.</li>
<li>TypedDict types cant be used in <code class="docutils literal notranslate"><span class="pre">isinstance()</span></code> or <code class="docutils literal notranslate"><span class="pre">issubclass()</span></code>
checks. The reasoning is similar to why runtime type checks arent
supported in general with many type hints.</li>
</ul>
<p>These features were left out from this PEP, but they are potential
extensions to be added in the future:</p>
<ul class="simple">
<li>TypedDict doesnt support providing a <em>default value type</em> for keys
that are not explicitly defined. This would allow arbitrary keys to
be used with a TypedDict object, and only explicitly enumerated keys
would receive special treatment compared to a normal, uniform
dictionary type.</li>
<li>There is no way to individually specify whether each key is required
or not. No proposed syntax was clear enough, and we expect that
there is limited need for this.</li>
<li>TypedDict cant be used for specifying the type of a <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code>
argument. This would allow restricting the allowed keyword
arguments and their types. According to <a class="pep reference internal" href="../pep-0484/" title="PEP 484 Type Hints">PEP 484</a>, using a TypedDict
type as the type of <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> means that the TypedDict is valid
as the <em>value</em> of arbitrary keyword arguments, but it doesnt
restrict which keyword arguments should be allowed. The syntax
<code class="docutils literal notranslate"><span class="pre">**kwargs:</span> <span class="pre">Expand[T]</span></code> has been proposed for this <a class="footnote-reference brackets" href="#expand" id="id6">[6]</a>.</li>
</ul>
</section>
<section id="acknowledgements">
<h2><a class="toc-backref" href="#acknowledgements" role="doc-backlink">Acknowledgements</a></h2>
<p>David Foster contributed the initial implementation of TypedDict types
to mypy. Improvements to the implementation have been contributed by
at least the author (Jukka Lehtosalo), Ivan Levkivskyi, Gareth T,
Michael Lee, Dominik Miedzinski, Roy Williams and Max Moroz.</p>
</section>
<section id="references">
<h2><a class="toc-backref" href="#references" role="doc-backlink">References</a></h2>
<aside class="footnote-list brackets">
<aside class="footnote brackets" id="dataclasses-json" role="doc-footnote">
<dt class="label" id="dataclasses-json">[<a href="#id1">1</a>]</dt>
<dd>Dataclasses JSON
(<a class="reference external" href="https://github.com/lidatong/dataclasses-json">https://github.com/lidatong/dataclasses-json</a>)</aside>
<aside class="footnote brackets" id="mypy" role="doc-footnote">
<dt class="label" id="mypy">[<a href="#id2">2</a>]</dt>
<dd><a class="reference external" href="http://www.mypy-lang.org/">http://www.mypy-lang.org/</a></aside>
<aside class="footnote brackets" id="typing-extensions" role="doc-footnote">
<dt class="label" id="typing-extensions">[<a href="#id3">3</a>]</dt>
<dd><a class="reference external" href="https://github.com/python/typing/tree/master/typing_extensions">https://github.com/python/typing/tree/master/typing_extensions</a></aside>
<aside class="footnote brackets" id="mypy-extensions" role="doc-footnote">
<dt class="label" id="mypy-extensions">[<a href="#id4">4</a>]</dt>
<dd><a class="reference external" href="https://github.com/python/mypy_extensions">https://github.com/python/mypy_extensions</a></aside>
<aside class="footnote brackets" id="typing-inspect" role="doc-footnote">
<dt class="label" id="typing-inspect">[<a href="#id5">5</a>]</dt>
<dd><a class="reference external" href="https://github.com/ilevkivskyi/typing_inspect">https://github.com/ilevkivskyi/typing_inspect</a></aside>
<aside class="footnote brackets" id="expand" role="doc-footnote">
<dt class="label" id="expand">[<a href="#id6">6</a>]</dt>
<dd><a class="reference external" href="https://github.com/python/mypy/issues/4441">https://github.com/python/mypy/issues/4441</a></aside>
</aside>
</section>
<section id="copyright">
<h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2>
<p>This document has been placed in the public domain.</p>
</section>
</section>
<hr class="docutils" />
<p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0589.rst">https://github.com/python/peps/blob/main/peps/pep-0589.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0589.rst">2024-06-11 22:12:09 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="#specification">Specification</a><ul>
<li><a class="reference internal" href="#class-based-syntax">Class-based Syntax</a></li>
<li><a class="reference internal" href="#using-typeddict-types">Using TypedDict Types</a></li>
<li><a class="reference internal" href="#inheritance">Inheritance</a></li>
<li><a class="reference internal" href="#totality">Totality</a></li>
<li><a class="reference internal" href="#alternative-syntax">Alternative Syntax</a></li>
<li><a class="reference internal" href="#type-consistency">Type Consistency</a></li>
<li><a class="reference internal" href="#supported-and-unsupported-operations">Supported and Unsupported Operations</a></li>
<li><a class="reference internal" href="#use-of-final-values-and-literal-types">Use of Final Values and Literal Types</a></li>
</ul>
</li>
<li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a></li>
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li>
<li><a class="reference internal" href="#rejected-alternatives">Rejected Alternatives</a></li>
<li><a class="reference internal" href="#acknowledgements">Acknowledgements</a></li>
<li><a class="reference internal" href="#references">References</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-0589.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>