CINXE.COM
PEP 696 – Type Defaults for Type Parameters | 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 696 – Type Defaults for Type Parameters | peps.python.org</title> <link rel="shortcut icon" href="../_static/py.png"> <link rel="canonical" href="https://peps.python.org/pep-0696/"> <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 696 – Type Defaults for Type Parameters | peps.python.org'> <meta property="og:description" content="This PEP introduces the concept of type defaults for type parameters, including TypeVar, ParamSpec, and TypeVarTuple, which act as defaults for type parameters for which no type is specified."> <meta property="og:type" content="website"> <meta property="og:url" content="https://peps.python.org/pep-0696/"> <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="This PEP introduces the concept of type defaults for type parameters, including TypeVar, ParamSpec, and TypeVarTuple, which act as defaults for type parameters for which no type is specified."> <meta name="theme-color" content="#3776ab"> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all"> <title>Following system colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="9"></circle> <path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path> </svg> </symbol> <symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all"> <title>Selected dark colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path stroke="none" d="M0 0h24v24H0z" fill="none"></path> <path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path> </svg> </symbol> <symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all"> <title>Selected light colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="5"></circle> <line x1="12" y1="1" x2="12" y2="3"></line> <line x1="12" y1="21" x2="12" y2="23"></line> <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line> <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line> <line x1="1" y1="12" x2="3" y2="12"></line> <line x1="21" y1="12" x2="23" y2="12"></line> <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line> <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line> </svg> </symbol> </svg> <script> document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto" </script> <section id="pep-page-section"> <header> <h1>Python Enhancement Proposals</h1> <ul class="breadcrumbs"> <li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> » </li> <li><a href="../pep-0000/">PEP Index</a> » </li> <li>PEP 696</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 696 – Type Defaults for Type Parameters</h1> <dl class="rfc2822 field-list simple"> <dt class="field-odd">Author<span class="colon">:</span></dt> <dd class="field-odd">James Hilton-Balfe <gobot1234yt at gmail.com></dd> <dt class="field-even">Sponsor<span class="colon">:</span></dt> <dd class="field-even">Jelle Zijlstra <jelle.zijlstra at gmail.com></dd> <dt class="field-odd">Discussions-To<span class="colon">:</span></dt> <dd class="field-odd"><a class="reference external" href="https://discuss.python.org/t/pep-696-type-defaults-for-typevarlikes/22569">Discourse thread</a></dd> <dt class="field-even">Status<span class="colon">:</span></dt> <dd class="field-even"><abbr title="Accepted and implementation complete, or no longer active">Final</abbr></dd> <dt class="field-odd">Type<span class="colon">:</span></dt> <dd class="field-odd"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd> <dt class="field-even">Topic<span class="colon">:</span></dt> <dd class="field-even"><a class="reference external" href="../topic/typing/">Typing</a></dd> <dt class="field-odd">Created<span class="colon">:</span></dt> <dd class="field-odd">14-Jul-2022</dd> <dt class="field-even">Python-Version<span class="colon">:</span></dt> <dd class="field-even">3.13</dd> <dt class="field-odd">Post-History<span class="colon">:</span></dt> <dd class="field-odd"><a class="reference external" href="https://mail.python.org/archives/list/typing-sig@python.org/thread/7VWBZWXTCX6RAJO6GG67BAXUPFZ24NTC/" title="Typing-SIG thread">22-Mar-2022</a>, <a class="reference external" href="https://discuss.python.org/t/pep-696-type-defaults-for-typevarlikes/22569/" title="Discourse thread">08-Jan-2023</a></dd> <dt class="field-even">Resolution<span class="colon">:</span></dt> <dd class="field-even"><a class="reference external" href="https://discuss.python.org/t/pep-696-type-defaults-for-typevarlikes/22569/34">Discourse 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="#default-ordering-and-subscription-rules">Default Ordering and Subscription Rules</a></li> <li><a class="reference internal" href="#paramspec-defaults"><code class="docutils literal notranslate"><span class="pre">ParamSpec</span></code> Defaults</a></li> <li><a class="reference internal" href="#typevartuple-defaults"><code class="docutils literal notranslate"><span class="pre">TypeVarTuple</span></code> Defaults</a></li> <li><a class="reference internal" href="#using-another-type-parameter-as-default">Using Another Type Parameter as <code class="docutils literal notranslate"><span class="pre">default</span></code></a><ul> <li><a class="reference internal" href="#scoping-rules">Scoping Rules</a></li> <li><a class="reference internal" href="#bound-rules">Bound Rules</a></li> <li><a class="reference internal" href="#constraint-rules">Constraint Rules</a></li> <li><a class="reference internal" href="#type-parameters-as-parameters-to-generics">Type Parameters as Parameters to Generics</a></li> <li><a class="reference internal" href="#specialisation-rules">Specialisation Rules</a></li> </ul> </li> <li><a class="reference internal" href="#generic-typealiases"><code class="docutils literal notranslate"><span class="pre">Generic</span></code> <code class="docutils literal notranslate"><span class="pre">TypeAlias</span></code>es</a></li> <li><a class="reference internal" href="#subclassing">Subclassing</a></li> <li><a class="reference internal" href="#using-bound-and-default">Using <code class="docutils literal notranslate"><span class="pre">bound</span></code> and <code class="docutils literal notranslate"><span class="pre">default</span></code></a></li> <li><a class="reference internal" href="#constraints">Constraints</a></li> <li><a class="reference internal" href="#function-defaults">Function Defaults</a></li> <li><a class="reference internal" href="#defaults-following-typevartuple">Defaults following <code class="docutils literal notranslate"><span class="pre">TypeVarTuple</span></code></a></li> <li><a class="reference internal" href="#subtyping">Subtyping</a></li> <li><a class="reference internal" href="#typevartuples-as-defaults"><code class="docutils literal notranslate"><span class="pre">TypeVarTuple</span></code>s as Defaults</a></li> </ul> </li> <li><a class="reference internal" href="#binding-rules">Binding rules</a></li> <li><a class="reference internal" href="#implementation">Implementation</a><ul> <li><a class="reference internal" href="#grammar-changes">Grammar changes</a></li> </ul> </li> <li><a class="reference internal" href="#rejected-alternatives">Rejected Alternatives</a><ul> <li><a class="reference internal" href="#allowing-the-type-parameters-defaults-to-be-passed-to-type-new-s-kwargs">Allowing the Type Parameters Defaults to Be Passed to <code class="docutils literal notranslate"><span class="pre">type.__new__</span></code>’s <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code></a></li> <li><a class="reference internal" href="#allowing-non-defaults-to-follow-defaults">Allowing Non-defaults to Follow Defaults</a></li> <li><a class="reference internal" href="#having-default-implicitly-be-bound">Having <code class="docutils literal notranslate"><span class="pre">default</span></code> Implicitly Be <code class="docutils literal notranslate"><span class="pre">bound</span></code></a></li> <li><a class="reference internal" href="#allowing-type-parameters-with-defaults-to-be-used-in-function-signatures">Allowing Type Parameters With Defaults To Be Used in Function Signatures</a></li> <li><a class="reference internal" href="#allowing-type-parameters-from-outer-scopes-in-default">Allowing Type Parameters from Outer Scopes in <code class="docutils literal notranslate"><span class="pre">default</span></code></a></li> </ul> </li> <li><a class="reference internal" href="#acknowledgements">Acknowledgements</a></li> <li><a class="reference internal" href="#copyright">Copyright</a></li> </ul> </details></section> <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/generics.html#type-parameter-defaults" title="(in typing)"><span>Defaults for Type Parameters</span></a> and <a class="reference external" href="https://docs.python.org/3.13/reference/compound_stmts.html#type-params" title="(in Python v3.13)"><span>Type parameter lists</span></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>This PEP introduces the concept of type defaults for type parameters, including <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code>, <code class="docutils literal notranslate"><span class="pre">ParamSpec</span></code>, and <code class="docutils literal notranslate"><span class="pre">TypeVarTuple</span></code>, which act as defaults for type parameters for which no type is specified.</p> <p>Default type argument support is available in some popular languages such as C++, TypeScript, and Rust. A survey of type parameter syntax in some common languages has been conducted by the author of <a class="pep reference internal" href="../pep-0695/" title="PEP 695 – Type Parameter Syntax">PEP 695</a> and can be found in its <a class="pep reference internal" href="../pep-0695/#appendix-a-survey-of-type-parameter-syntax" title="PEP 695 – Type Parameter Syntax § Appendix A: Survey of Type Parameter Syntax">Appendix A</a>.</p> </section> <section id="motivation"> <h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">T</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"T"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span> <span class="c1"># This means that if no type is specified T = int</span> <span class="nd">@dataclass</span> <span class="k">class</span> <span class="nc">Box</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">T</span><span class="p">]):</span> <span class="n">value</span><span class="p">:</span> <span class="n">T</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">Box</span><span class="p">())</span> <span class="c1"># type is Box[int]</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">Box</span><span class="p">(</span><span class="n">value</span><span class="o">=</span><span class="s2">"Hello World!"</span><span class="p">))</span> <span class="c1"># type is Box[str]</span> </pre></div> </div> <p>One place this <a class="reference external" href="https://github.com/python/typing/issues/975">regularly comes up</a> is <code class="docutils literal notranslate"><span class="pre">Generator</span></code>. I propose changing the <em>stub definition</em> to something like:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">YieldT</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"YieldT"</span><span class="p">)</span> <span class="n">SendT</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"SendT"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span> <span class="n">ReturnT</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"ReturnT"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span> <span class="k">class</span> <span class="nc">Generator</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">YieldT</span><span class="p">,</span> <span class="n">SendT</span><span class="p">,</span> <span class="n">ReturnT</span><span class="p">]):</span> <span class="o">...</span> <span class="n">Generator</span><span class="p">[</span><span class="nb">int</span><span class="p">]</span> <span class="o">==</span> <span class="n">Generator</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="kc">None</span><span class="p">]</span> <span class="o">==</span> <span class="n">Generator</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">]</span> </pre></div> </div> <p>This is also useful for a <code class="docutils literal notranslate"><span class="pre">Generic</span></code> that is commonly over one type.</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Bot</span><span class="p">:</span> <span class="o">...</span> <span class="n">BotT</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"BotT"</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="n">Bot</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">Bot</span><span class="p">)</span> <span class="k">class</span> <span class="nc">Context</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">BotT</span><span class="p">]):</span> <span class="n">bot</span><span class="p">:</span> <span class="n">BotT</span> <span class="k">class</span> <span class="nc">MyBot</span><span class="p">(</span><span class="n">Bot</span><span class="p">):</span> <span class="o">...</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">Context</span><span class="p">()</span><span class="o">.</span><span class="n">bot</span><span class="p">)</span> <span class="c1"># type is Bot # notice this is not Any which is what it would be currently</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">Context</span><span class="p">[</span><span class="n">MyBot</span><span class="p">]()</span><span class="o">.</span><span class="n">bot</span><span class="p">)</span> <span class="c1"># type is MyBot</span> </pre></div> </div> <p>Not only does this improve typing for those who explicitly use it, it also helps non-typing users who rely on auto-complete to speed up their development.</p> <p>This design pattern is common in projects like:</p> <ul class="simple"> <li><a class="reference external" href="https://github.com/Rapptz/discord.py">discord.py</a> — where the example above was taken from.</li> <li><a class="reference external" href="https://github.com/numpy/numpy">NumPy</a> — the default for types like <code class="docutils literal notranslate"><span class="pre">ndarray</span></code>’s <code class="docutils literal notranslate"><span class="pre">dtype</span></code> would be <code class="docutils literal notranslate"><span class="pre">float64</span></code>. Currently it’s <code class="docutils literal notranslate"><span class="pre">Unknown</span></code> or <code class="docutils literal notranslate"><span class="pre">Any</span></code>.</li> <li><a class="reference external" href="https://github.com/tensorflow/tensorflow">TensorFlow</a> — this could be used for Tensor similarly to <code class="docutils literal notranslate"><span class="pre">numpy.ndarray</span></code> and would be useful to simplify the definition of <code class="docutils literal notranslate"><span class="pre">Layer</span></code>.</li> </ul> </section> <section id="specification"> <h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2> <section id="default-ordering-and-subscription-rules"> <h3><a class="toc-backref" href="#default-ordering-and-subscription-rules" role="doc-backlink">Default Ordering and Subscription Rules</a></h3> <p>The order for defaults should follow the standard function parameter rules, so a type parameter with no <code class="docutils literal notranslate"><span class="pre">default</span></code> cannot follow one with a <code class="docutils literal notranslate"><span class="pre">default</span></code> value. Doing so should ideally raise a <code class="docutils literal notranslate"><span class="pre">TypeError</span></code> in <code class="docutils literal notranslate"><span class="pre">typing._GenericAlias</span></code>/<code class="docutils literal notranslate"><span class="pre">types.GenericAlias</span></code>, and a type checker should flag this as an error.</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">DefaultStrT</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"DefaultStrT"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="nb">str</span><span class="p">)</span> <span class="n">DefaultIntT</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"DefaultIntT"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span> <span class="n">DefaultBoolT</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"DefaultBoolT"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="nb">bool</span><span class="p">)</span> <span class="n">T</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"T"</span><span class="p">)</span> <span class="n">T2</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"T2"</span><span class="p">)</span> <span class="k">class</span> <span class="nc">NonDefaultFollowsDefault</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">DefaultStrT</span><span class="p">,</span> <span class="n">T</span><span class="p">]):</span> <span class="o">...</span> <span class="c1"># Invalid: non-default TypeVars cannot follow ones with defaults</span> <span class="k">class</span> <span class="nc">NoNonDefaults</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">DefaultStrT</span><span class="p">,</span> <span class="n">DefaultIntT</span><span class="p">]):</span> <span class="o">...</span> <span class="p">(</span> <span class="n">NoNoneDefaults</span> <span class="o">==</span> <span class="n">NoNoneDefaults</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">==</span> <span class="n">NoNoneDefaults</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="p">)</span> <span class="c1"># All valid</span> <span class="k">class</span> <span class="nc">OneDefault</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">T</span><span class="p">,</span> <span class="n">DefaultBoolT</span><span class="p">]):</span> <span class="o">...</span> <span class="n">OneDefault</span><span class="p">[</span><span class="nb">float</span><span class="p">]</span> <span class="o">==</span> <span class="n">OneDefault</span><span class="p">[</span><span class="nb">float</span><span class="p">,</span> <span class="nb">bool</span><span class="p">]</span> <span class="c1"># Valid</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">OneDefault</span><span class="p">)</span> <span class="c1"># type is type[OneDefault[T, DefaultBoolT = bool]]</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">OneDefault</span><span class="p">[</span><span class="nb">float</span><span class="p">]())</span> <span class="c1"># type is OneDefault[float, bool]</span> <span class="k">class</span> <span class="nc">AllTheDefaults</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">T1</span><span class="p">,</span> <span class="n">T2</span><span class="p">,</span> <span class="n">DefaultStrT</span><span class="p">,</span> <span class="n">DefaultIntT</span><span class="p">,</span> <span class="n">DefaultBoolT</span><span class="p">]):</span> <span class="o">...</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">AllTheDefaults</span><span class="p">)</span> <span class="c1"># type is type[AllTheDefaults[T1, T2, DefaultStrT = str, DefaultIntT = int, DefaultBoolT = bool]]</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">AllTheDefaults</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">complex</span><span class="p">]())</span> <span class="c1"># type is AllTheDefaults[int, complex, str, int, bool]</span> <span class="n">AllTheDefaults</span><span class="p">[</span><span class="nb">int</span><span class="p">]</span> <span class="c1"># Invalid: expected 2 arguments to AllTheDefaults</span> <span class="p">(</span> <span class="n">AllTheDefaults</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">complex</span><span class="p">]</span> <span class="o">==</span> <span class="n">AllTheDefaults</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">complex</span><span class="p">,</span> <span class="nb">str</span><span class="p">]</span> <span class="o">==</span> <span class="n">AllTheDefaults</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">complex</span><span class="p">,</span> <span class="nb">str</span><span class="p">,</span> <span class="nb">int</span><span class="p">]</span> <span class="o">==</span> <span class="n">AllTheDefaults</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">complex</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="nb">bool</span><span class="p">]</span> <span class="p">)</span> <span class="c1"># All valid</span> </pre></div> </div> <p>With the new Python 3.12 syntax for generics (introduced by <a class="pep reference internal" href="../pep-0695/" title="PEP 695 – Type Parameter Syntax">PEP 695</a>), this can be enforced at compile time:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nb">type</span> <span class="n">Alias</span><span class="p">[</span><span class="n">DefaultT</span> <span class="o">=</span> <span class="nb">int</span><span class="p">,</span> <span class="n">T</span><span class="p">]</span> <span class="o">=</span> <span class="nb">tuple</span><span class="p">[</span><span class="n">DefaultT</span><span class="p">,</span> <span class="n">T</span><span class="p">]</span> <span class="c1"># SyntaxError: non-default TypeVars cannot follow ones with defaults</span> <span class="k">def</span> <span class="nf">generic_func</span><span class="p">[</span><span class="n">DefaultT</span> <span class="o">=</span> <span class="nb">int</span><span class="p">,</span> <span class="n">T</span><span class="p">](</span><span class="n">x</span><span class="p">:</span> <span class="n">DefaultT</span><span class="p">,</span> <span class="n">y</span><span class="p">:</span> <span class="n">T</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span> <span class="o">...</span> <span class="c1"># SyntaxError: non-default TypeVars cannot follow ones with defaults</span> <span class="k">class</span> <span class="nc">GenericClass</span><span class="p">[</span><span class="n">DefaultT</span> <span class="o">=</span> <span class="nb">int</span><span class="p">,</span> <span class="n">T</span><span class="p">]:</span> <span class="o">...</span> <span class="c1"># SyntaxError: non-default TypeVars cannot follow ones with defaults</span> </pre></div> </div> </section> <section id="paramspec-defaults"> <h3><a class="toc-backref" href="#paramspec-defaults" role="doc-backlink"><code class="docutils literal notranslate"><span class="pre">ParamSpec</span></code> Defaults</a></h3> <p><code class="docutils literal notranslate"><span class="pre">ParamSpec</span></code> defaults are defined using the same syntax as <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code> s but use a <code class="docutils literal notranslate"><span class="pre">list</span></code> of types or an ellipsis literal “<code class="docutils literal notranslate"><span class="pre">...</span></code>” or another in-scope <code class="docutils literal notranslate"><span class="pre">ParamSpec</span></code> (see <a class="reference internal" href="#scoping-rules">Scoping Rules</a>).</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">DefaultP</span> <span class="o">=</span> <span class="n">ParamSpec</span><span class="p">(</span><span class="s2">"DefaultP"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</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="k">class</span> <span class="nc">Foo</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">DefaultP</span><span class="p">]):</span> <span class="o">...</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">Foo</span><span class="p">)</span> <span class="c1"># type is type[Foo[DefaultP = [str, int]]]</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">Foo</span><span class="p">())</span> <span class="c1"># type is Foo[[str, int]]</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">Foo</span><span class="p">[[</span><span class="nb">bool</span><span class="p">,</span> <span class="nb">bool</span><span class="p">]]())</span> <span class="c1"># type is Foo[[bool, bool]]</span> </pre></div> </div> </section> <section id="typevartuple-defaults"> <h3><a class="toc-backref" href="#typevartuple-defaults" role="doc-backlink"><code class="docutils literal notranslate"><span class="pre">TypeVarTuple</span></code> Defaults</a></h3> <p><code class="docutils literal notranslate"><span class="pre">TypeVarTuple</span></code> defaults are defined using the same syntax as <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code> s but use an unpacked tuple of types instead of a single type or another in-scope <code class="docutils literal notranslate"><span class="pre">TypeVarTuple</span></code> (see <a class="reference internal" href="#scoping-rules">Scoping Rules</a>).</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">DefaultTs</span> <span class="o">=</span> <span class="n">TypeVarTuple</span><span class="p">(</span><span class="s2">"DefaultTs"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">Unpack</span><span class="p">[</span><span class="nb">tuple</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="k">class</span> <span class="nc">Foo</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="o">*</span><span class="n">DefaultTs</span><span class="p">]):</span> <span class="o">...</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">Foo</span><span class="p">)</span> <span class="c1"># type is type[Foo[DefaultTs = *tuple[str, int]]]</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">Foo</span><span class="p">())</span> <span class="c1"># type is Foo[str, int]</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">Foo</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">bool</span><span class="p">]())</span> <span class="c1"># type is Foo[int, bool]</span> </pre></div> </div> </section> <section id="using-another-type-parameter-as-default"> <h3><a class="toc-backref" href="#using-another-type-parameter-as-default" role="doc-backlink">Using Another Type Parameter as <code class="docutils literal notranslate"><span class="pre">default</span></code></a></h3> <p>This allows for a value to be used again when the type parameter to a generic is missing but another type parameter is specified.</p> <p>To use another type parameter as a default the <code class="docutils literal notranslate"><span class="pre">default</span></code> and the type parameter must be the same type (a <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code>’s default must be a <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code>, etc.).</p> <p><a class="reference external" href="https://github.com/python/typing/issues/159">This could be used on builtins.slice</a> where the <code class="docutils literal notranslate"><span class="pre">start</span></code> parameter should default to <code class="docutils literal notranslate"><span class="pre">int</span></code>, <code class="docutils literal notranslate"><span class="pre">stop</span></code> default to the type of <code class="docutils literal notranslate"><span class="pre">start</span></code> and step default to <code class="docutils literal notranslate"><span class="pre">int</span> <span class="pre">|</span> <span class="pre">None</span></code>.</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">StartT</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"StartT"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span> <span class="n">StopT</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"StopT"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">StartT</span><span class="p">)</span> <span class="n">StepT</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"StepT"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="nb">int</span> <span class="o">|</span> <span class="kc">None</span><span class="p">)</span> <span class="k">class</span> <span class="nc">slice</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">StartT</span><span class="p">,</span> <span class="n">StopT</span><span class="p">,</span> <span class="n">StepT</span><span class="p">]):</span> <span class="o">...</span> <span class="n">reveal_type</span><span class="p">(</span><span class="nb">slice</span><span class="p">)</span> <span class="c1"># type is type[slice[StartT = int, StopT = StartT, StepT = int | None]]</span> <span class="n">reveal_type</span><span class="p">(</span><span class="nb">slice</span><span class="p">())</span> <span class="c1"># type is slice[int, int, int | None]</span> <span class="n">reveal_type</span><span class="p">(</span><span class="nb">slice</span><span class="p">[</span><span class="nb">str</span><span class="p">]())</span> <span class="c1"># type is slice[str, str, int | None]</span> <span class="n">reveal_type</span><span class="p">(</span><span class="nb">slice</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">bool</span><span class="p">,</span> <span class="n">timedelta</span><span class="p">]())</span> <span class="c1"># type is slice[str, bool, timedelta]</span> <span class="n">T2</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"T2"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">DefaultStrT</span><span class="p">)</span> <span class="k">class</span> <span class="nc">Foo</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">DefaultStrT</span><span class="p">,</span> <span class="n">T2</span><span class="p">]):</span> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">a</span><span class="p">:</span> <span class="n">DefaultStrT</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span> <span class="n">T2</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span> <span class="o">...</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">Foo</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="s2">""</span><span class="p">))</span> <span class="c1"># type is Foo[int, str]</span> <span class="n">Foo</span><span class="p">[</span><span class="nb">int</span><span class="p">](</span><span class="mi">1</span><span class="p">,</span> <span class="s2">""</span><span class="p">)</span> <span class="c1"># Invalid: Foo[int, str] cannot be assigned to self: Foo[int, int] in Foo.__init__</span> <span class="n">Foo</span><span class="p">[</span><span class="nb">int</span><span class="p">](</span><span class="s2">""</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="c1"># Invalid: Foo[str, int] cannot be assigned to self: Foo[int, int] in Foo.__init__</span> </pre></div> </div> <p>When using a type parameter as the default to another type parameter, the following rules apply, where <code class="docutils literal notranslate"><span class="pre">T1</span></code> is the default for <code class="docutils literal notranslate"><span class="pre">T2</span></code>.</p> <section id="scoping-rules"> <h4><a class="toc-backref" href="#scoping-rules" role="doc-backlink">Scoping Rules</a></h4> <p><code class="docutils literal notranslate"><span class="pre">T1</span></code> must be used before <code class="docutils literal notranslate"><span class="pre">T2</span></code> in the parameter list of the generic.</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">T2</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"T2"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">T1</span><span class="p">)</span> <span class="k">class</span> <span class="nc">Foo</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">T1</span><span class="p">,</span> <span class="n">T2</span><span class="p">]):</span> <span class="o">...</span> <span class="c1"># Valid</span> <span class="k">class</span> <span class="nc">Foo</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">T1</span><span class="p">]):</span> <span class="k">class</span> <span class="nc">Bar</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">T2</span><span class="p">]):</span> <span class="o">...</span> <span class="c1"># Valid</span> <span class="n">StartT</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"StartT"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s2">"StopT"</span><span class="p">)</span> <span class="c1"># Swapped defaults around from previous example</span> <span class="n">StopT</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"StopT"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span> <span class="k">class</span> <span class="nc">slice</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">StartT</span><span class="p">,</span> <span class="n">StopT</span><span class="p">,</span> <span class="n">StepT</span><span class="p">]):</span> <span class="o">...</span> <span class="c1"># ^^^^^^ Invalid: ordering does not allow StopT to be bound</span> </pre></div> </div> <p>Using a type parameter from an outer scope as a default is not supported.</p> </section> <section id="bound-rules"> <h4><a class="toc-backref" href="#bound-rules" role="doc-backlink">Bound Rules</a></h4> <p><code class="docutils literal notranslate"><span class="pre">T1</span></code>’s bound must be a subtype of <code class="docutils literal notranslate"><span class="pre">T2</span></code>’s bound.</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">T1</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"T1"</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"Ok"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">T1</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="nb">float</span><span class="p">)</span> <span class="c1"># Valid</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"AlsoOk"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">T1</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span> <span class="c1"># Valid</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"Invalid"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">T1</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="nb">str</span><span class="p">)</span> <span class="c1"># Invalid: int is not a subtype of str</span> </pre></div> </div> </section> <section id="constraint-rules"> <h4><a class="toc-backref" href="#constraint-rules" role="doc-backlink">Constraint Rules</a></h4> <p>The constraints of <code class="docutils literal notranslate"><span class="pre">T2</span></code> must be a superset of the constraints of <code class="docutils literal notranslate"><span class="pre">T1</span></code>.</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">T1</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"T1"</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"Invalid"</span><span class="p">,</span> <span class="nb">float</span><span class="p">,</span> <span class="nb">str</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">T1</span><span class="p">)</span> <span class="c1"># Invalid: upper bound int is incompatible with constraints float or str</span> <span class="n">T1</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"T1"</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="n">TypeVar</span><span class="p">(</span><span class="s2">"AlsoOk"</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="nb">bool</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">T1</span><span class="p">)</span> <span class="c1"># Valid</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"AlsoInvalid"</span><span class="p">,</span> <span class="nb">bool</span><span class="p">,</span> <span class="nb">complex</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">T1</span><span class="p">)</span> <span class="c1"># Invalid: {bool, complex} is not a superset of {int, str}</span> </pre></div> </div> </section> <section id="type-parameters-as-parameters-to-generics"> <h4><a class="toc-backref" href="#type-parameters-as-parameters-to-generics" role="doc-backlink">Type Parameters as Parameters to Generics</a></h4> <p>Type parameters are valid as parameters to generics inside of a <code class="docutils literal notranslate"><span class="pre">default</span></code> when the first parameter is in scope as determined by the <a class="reference internal" href="#scoping-rules">previous section</a>.</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">T</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"T"</span><span class="p">)</span> <span class="n">ListDefaultT</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"ListDefaultT"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="nb">list</span><span class="p">[</span><span class="n">T</span><span class="p">])</span> <span class="k">class</span> <span class="nc">Bar</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">T</span><span class="p">,</span> <span class="n">ListDefaultT</span><span class="p">]):</span> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="p">:</span> <span class="n">T</span><span class="p">,</span> <span class="n">y</span><span class="p">:</span> <span class="n">ListDefaultT</span><span class="p">):</span> <span class="o">...</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">Bar</span><span class="p">)</span> <span class="c1"># type is type[Bar[T, ListDefaultT = list[T]]]</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">Bar</span><span class="p">[</span><span class="nb">int</span><span class="p">])</span> <span class="c1"># type is type[Bar[int, list[int]]]</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">Bar</span><span class="p">[</span><span class="nb">int</span><span class="p">]())</span> <span class="c1"># type is Bar[int, list[int]]</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">Bar</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]]())</span> <span class="c1"># type is Bar[int, list[str]]</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">Bar</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="c1"># type is Bar[int, str]</span> </pre></div> </div> </section> <section id="specialisation-rules"> <h4><a class="toc-backref" href="#specialisation-rules" role="doc-backlink">Specialisation Rules</a></h4> <p>Type parameters currently cannot be further subscripted. This might change if <a class="reference external" href="https://github.com/python/typing/issues/548">Higher Kinded TypeVars</a> are implemented.</p> </section> </section> <section id="generic-typealiases"> <h3><a class="toc-backref" href="#generic-typealiases" role="doc-backlink"><code class="docutils literal notranslate"><span class="pre">Generic</span></code> <code class="docutils literal notranslate"><span class="pre">TypeAlias</span></code>es</a></h3> <p><code class="docutils literal notranslate"><span class="pre">Generic</span></code> <code class="docutils literal notranslate"><span class="pre">TypeAlias</span></code>es should be able to be further subscripted following normal subscription rules. If a type parameter has a default that hasn’t been overridden it should be treated like it was substituted into the <code class="docutils literal notranslate"><span class="pre">TypeAlias</span></code>. However, it can be specialised further down the line.</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">SomethingWithNoDefaults</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">T</span><span class="p">,</span> <span class="n">T2</span><span class="p">]):</span> <span class="o">...</span> <span class="n">MyAlias</span><span class="p">:</span> <span class="n">TypeAlias</span> <span class="o">=</span> <span class="n">SomethingWithNoDefaults</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="n">DefaultStrT</span><span class="p">]</span> <span class="c1"># Valid</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">MyAlias</span><span class="p">)</span> <span class="c1"># type is type[SomethingWithNoDefaults[int, DefaultStrT]]</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">MyAlias</span><span class="p">[</span><span class="nb">bool</span><span class="p">]())</span> <span class="c1"># type is SomethingWithNoDefaults[int, bool]</span> <span class="n">MyAlias</span><span class="p">[</span><span class="nb">bool</span><span class="p">,</span> <span class="nb">int</span><span class="p">]</span> <span class="c1"># Invalid: too many arguments passed to MyAlias</span> </pre></div> </div> </section> <section id="subclassing"> <h3><a class="toc-backref" href="#subclassing" role="doc-backlink">Subclassing</a></h3> <p>Subclasses of <code class="docutils literal notranslate"><span class="pre">Generic</span></code>s with type parameters that have defaults behave similarly to <code class="docutils literal notranslate"><span class="pre">Generic</span></code> <code class="docutils literal notranslate"><span class="pre">TypeAlias</span></code>es. That is, subclasses can be further subscripted following normal subscription rules, non-overridden defaults should be substituted in, and type parameters with such defaults can be further specialised down the line.</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">SubclassMe</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">T</span><span class="p">,</span> <span class="n">DefaultStrT</span><span class="p">]):</span> <span class="n">x</span><span class="p">:</span> <span class="n">DefaultStrT</span> <span class="k">class</span> <span class="nc">Bar</span><span class="p">(</span><span class="n">SubclassMe</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="n">DefaultStrT</span><span class="p">]):</span> <span class="o">...</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">Bar</span><span class="p">)</span> <span class="c1"># type is type[Bar[DefaultStrT = str]]</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">Bar</span><span class="p">())</span> <span class="c1"># type is Bar[str]</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">Bar</span><span class="p">[</span><span class="nb">bool</span><span class="p">]())</span> <span class="c1"># type is Bar[bool]</span> <span class="k">class</span> <span class="nc">Foo</span><span class="p">(</span><span class="n">SubclassMe</span><span class="p">[</span><span class="nb">float</span><span class="p">]):</span> <span class="o">...</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">Foo</span><span class="p">()</span><span class="o">.</span><span class="n">x</span><span class="p">)</span> <span class="c1"># type is str</span> <span class="n">Foo</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="c1"># Invalid: Foo cannot be further subscripted</span> <span class="k">class</span> <span class="nc">Baz</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">DefaultIntT</span><span class="p">,</span> <span class="n">DefaultStrT</span><span class="p">]):</span> <span class="o">...</span> <span class="k">class</span> <span class="nc">Spam</span><span class="p">(</span><span class="n">Baz</span><span class="p">):</span> <span class="o">...</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">Spam</span><span class="p">())</span> <span class="c1"># type is <subclass of Baz[int, str]></span> </pre></div> </div> </section> <section id="using-bound-and-default"> <h3><a class="toc-backref" href="#using-bound-and-default" role="doc-backlink">Using <code class="docutils literal notranslate"><span class="pre">bound</span></code> and <code class="docutils literal notranslate"><span class="pre">default</span></code></a></h3> <p>If both <code class="docutils literal notranslate"><span class="pre">bound</span></code> and <code class="docutils literal notranslate"><span class="pre">default</span></code> are passed <code class="docutils literal notranslate"><span class="pre">default</span></code> must be a subtype of <code class="docutils literal notranslate"><span class="pre">bound</span></code>. Otherwise the type checker should generate an error.</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">TypeVar</span><span class="p">(</span><span class="s2">"Ok"</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="nb">float</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span> <span class="c1"># Valid</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"Invalid"</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="nb">str</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span> <span class="c1"># Invalid: the bound and default are incompatible</span> </pre></div> </div> </section> <section id="constraints"> <h3><a class="toc-backref" href="#constraints" role="doc-backlink">Constraints</a></h3> <p>For constrained <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code>s, the default needs to be one of the constraints. A type checker should generate an error even if it is a subtype of one of the constraints.</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">TypeVar</span><span class="p">(</span><span class="s2">"Ok"</span><span class="p">,</span> <span class="nb">float</span><span class="p">,</span> <span class="nb">str</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="nb">float</span><span class="p">)</span> <span class="c1"># Valid</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"Invalid"</span><span class="p">,</span> <span class="nb">float</span><span class="p">,</span> <span class="nb">str</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span> <span class="c1"># Invalid: expected one of float or str got int</span> </pre></div> </div> </section> <section id="function-defaults"> <span id="id1"></span><h3><a class="toc-backref" href="#function-defaults" role="doc-backlink">Function Defaults</a></h3> <p>In generic functions, type checkers may use a type parameter’s default when the type parameter cannot be solved to anything. We leave the semantics of this usage unspecified, as ensuring the <code class="docutils literal notranslate"><span class="pre">default</span></code> is returned in every code path where the type parameter can go unsolved may be too hard to implement. Type checkers are free to either disallow this case or experiment with implementing support.</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">T</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s1">'T'</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span> <span class="k">def</span> <span class="nf">func</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="nb">int</span> <span class="o">|</span> <span class="nb">set</span><span class="p">[</span><span class="n">T</span><span class="p">])</span> <span class="o">-></span> <span class="n">T</span><span class="p">:</span> <span class="o">...</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">func</span><span class="p">(</span><span class="mi">0</span><span class="p">))</span> <span class="c1"># a type checker may reveal T's default of int here</span> </pre></div> </div> </section> <section id="defaults-following-typevartuple"> <h3><a class="toc-backref" href="#defaults-following-typevartuple" role="doc-backlink">Defaults following <code class="docutils literal notranslate"><span class="pre">TypeVarTuple</span></code></a></h3> <p>A <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code> that immediately follows a <code class="docutils literal notranslate"><span class="pre">TypeVarTuple</span></code> is not allowed to have a default, because it would be ambiguous whether a type argument should be bound to the <code class="docutils literal notranslate"><span class="pre">TypeVarTuple</span></code> or the defaulted <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code>.</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Ts</span> <span class="o">=</span> <span class="n">TypeVarTuple</span><span class="p">(</span><span class="s2">"Ts"</span><span class="p">)</span> <span class="n">T</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"T"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="nb">bool</span><span class="p">)</span> <span class="k">class</span> <span class="nc">Foo</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">Ts</span><span class="p">,</span> <span class="n">T</span><span class="p">]):</span> <span class="o">...</span> <span class="c1"># Type checker error</span> <span class="c1"># Could be reasonably interpreted as either Ts = (int, str, float), T = bool</span> <span class="c1"># or Ts = (int, str), T = float</span> <span class="n">Foo</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="nb">float</span><span class="p">]</span> </pre></div> </div> <p>With the Python 3.12 built-in generic syntax, this case should raise a SyntaxError.</p> <p>However, it is allowed to have a <code class="docutils literal notranslate"><span class="pre">ParamSpec</span></code> with a default following a <code class="docutils literal notranslate"><span class="pre">TypeVarTuple</span></code> with a default, as there can be no ambiguity between a type argument for the <code class="docutils literal notranslate"><span class="pre">ParamSpec</span></code> and one for the <code class="docutils literal notranslate"><span class="pre">TypeVarTuple</span></code>.</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Ts</span> <span class="o">=</span> <span class="n">TypeVarTuple</span><span class="p">(</span><span class="s2">"Ts"</span><span class="p">)</span> <span class="n">P</span> <span class="o">=</span> <span class="n">ParamSpec</span><span class="p">(</span><span class="s2">"P"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="p">[</span><span class="nb">float</span><span class="p">,</span> <span class="nb">bool</span><span class="p">])</span> <span class="k">class</span> <span class="nc">Foo</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">Ts</span><span class="p">,</span> <span class="n">P</span><span class="p">]):</span> <span class="o">...</span> <span class="c1"># Valid</span> <span class="n">Foo</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="c1"># Ts = (int, str), P = [float, bool]</span> <span class="n">Foo</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="p">[</span><span class="nb">bytes</span><span class="p">]]</span> <span class="c1"># Ts = (int, str), P = [bytes]</span> </pre></div> </div> </section> <section id="subtyping"> <h3><a class="toc-backref" href="#subtyping" role="doc-backlink">Subtyping</a></h3> <p>Type parameter defaults do not affect the subtyping rules for generic classes. In particular, defaults can be ignored when considering whether a class is compatible with a generic protocol.</p> </section> <section id="typevartuples-as-defaults"> <h3><a class="toc-backref" href="#typevartuples-as-defaults" role="doc-backlink"><code class="docutils literal notranslate"><span class="pre">TypeVarTuple</span></code>s as Defaults</a></h3> <p>Using a <code class="docutils literal notranslate"><span class="pre">TypeVarTuple</span></code> as a default is not supported because:</p> <ul class="simple"> <li><a class="reference internal" href="#scoping-rules">Scoping Rules</a> does not allow usage of type parameters from outer scopes.</li> <li>Multiple <code class="docutils literal notranslate"><span class="pre">TypeVarTuple</span></code>s cannot appear in the type parameter list for a single object, as specified in <a class="pep reference internal" href="../pep-0646/#multiple-type-variable-tuples-not-allowed" title="PEP 646 – Variadic Generics § Multiple Type Variable Tuples: Not Allowed">PEP 646</a>.</li> </ul> <p>These reasons leave no current valid location where a <code class="docutils literal notranslate"><span class="pre">TypeVarTuple</span></code> could be used as the default of another <code class="docutils literal notranslate"><span class="pre">TypeVarTuple</span></code>.</p> </section> </section> <section id="binding-rules"> <h2><a class="toc-backref" href="#binding-rules" role="doc-backlink">Binding rules</a></h2> <p>Type parameter defaults should be bound by attribute access (including call and subscript).</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Foo</span><span class="p">[</span><span class="n">T</span> <span class="o">=</span> <span class="nb">int</span><span class="p">]:</span> <span class="k">def</span> <span class="nf">meth</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">Self</span><span class="p">:</span> <span class="k">return</span> <span class="bp">self</span> <span class="n">reveal_type</span><span class="p">(</span><span class="n">Foo</span><span class="o">.</span><span class="n">meth</span><span class="p">)</span> <span class="c1"># type is (self: Foo[int]) -> Foo[int]</span> </pre></div> </div> </section> <section id="implementation"> <h2><a class="toc-backref" href="#implementation" role="doc-backlink">Implementation</a></h2> <p>At runtime, this would involve the following changes to the <code class="docutils literal notranslate"><span class="pre">typing</span></code> module.</p> <ul class="simple"> <li>The classes <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code>, <code class="docutils literal notranslate"><span class="pre">ParamSpec</span></code>, and <code class="docutils literal notranslate"><span class="pre">TypeVarTuple</span></code> should expose the type passed to <code class="docutils literal notranslate"><span class="pre">default</span></code>. This would be available as a <code class="docutils literal notranslate"><span class="pre">__default__</span></code> attribute, which would be <code class="docutils literal notranslate"><span class="pre">None</span></code> if no argument is passed and <code class="docutils literal notranslate"><span class="pre">NoneType</span></code> if <code class="docutils literal notranslate"><span class="pre">default=None</span></code>.</li> </ul> <p>The following changes would be required to both <code class="docutils literal notranslate"><span class="pre">GenericAlias</span></code>es:</p> <ul class="simple"> <li>logic to determine the defaults required for a subscription.</li> <li>ideally, logic to determine if subscription (like <code class="docutils literal notranslate"><span class="pre">Generic[T,</span> <span class="pre">DefaultT]</span></code>) would be valid.</li> </ul> <p>The grammar for type parameter lists would need to be updated to allow defaults; see below.</p> <p>A reference implementation of the runtime changes can be found at <a class="reference external" href="https://github.com/Gobot1234/cpython/tree/pep-696">https://github.com/Gobot1234/cpython/tree/pep-696</a></p> <p>A reference implementation of the type checker can be found at <a class="reference external" href="https://github.com/Gobot1234/mypy/tree/TypeVar-defaults">https://github.com/Gobot1234/mypy/tree/TypeVar-defaults</a></p> <p>Pyright currently supports this functionality.</p> <section id="grammar-changes"> <h3><a class="toc-backref" href="#grammar-changes" role="doc-backlink">Grammar changes</a></h3> <p>The syntax added in <a class="pep reference internal" href="../pep-0695/" title="PEP 695 – Type Parameter Syntax">PEP 695</a> will be extended to introduce a way to specify defaults for type parameters using the “=” operator inside of the square brackets like so:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># TypeVars</span> <span class="k">class</span> <span class="nc">Foo</span><span class="p">[</span><span class="n">T</span> <span class="o">=</span> <span class="nb">str</span><span class="p">]:</span> <span class="o">...</span> <span class="c1"># ParamSpecs</span> <span class="k">class</span> <span class="nc">Baz</span><span class="p">[</span><span class="o">**</span><span class="n">P</span> <span class="o">=</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="o">...</span> <span class="c1"># TypeVarTuples</span> <span class="k">class</span> <span class="nc">Qux</span><span class="p">[</span><span class="o">*</span><span class="n">Ts</span> <span class="o">=</span> <span class="o">*</span><span class="nb">tuple</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">bool</span><span class="p">]]:</span> <span class="o">...</span> <span class="c1"># TypeAliases</span> <span class="nb">type</span> <span class="n">Foo</span><span class="p">[</span><span class="n">T</span><span class="p">,</span> <span class="n">U</span> <span class="o">=</span> <span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="n">Bar</span><span class="p">[</span><span class="n">T</span><span class="p">,</span> <span class="n">U</span><span class="p">]</span> <span class="nb">type</span> <span class="n">Baz</span><span class="p">[</span><span class="o">**</span><span class="n">P</span> <span class="o">=</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="o">=</span> <span class="n">Spam</span><span class="p">[</span><span class="o">**</span><span class="n">P</span><span class="p">]</span> <span class="nb">type</span> <span class="n">Qux</span><span class="p">[</span><span class="o">*</span><span class="n">Ts</span> <span class="o">=</span> <span class="o">*</span><span class="nb">tuple</span><span class="p">[</span><span class="nb">str</span><span class="p">]]</span> <span class="o">=</span> <span class="n">Ham</span><span class="p">[</span><span class="o">*</span><span class="n">Ts</span><span class="p">]</span> <span class="nb">type</span> <span class="n">Rab</span><span class="p">[</span><span class="n">U</span><span class="p">,</span> <span class="n">T</span> <span class="o">=</span> <span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="n">Bar</span><span class="p">[</span><span class="n">T</span><span class="p">,</span> <span class="n">U</span><span class="p">]</span> </pre></div> </div> <p><a class="reference internal" href="../pep-0695/#scoping-behavior"><span class="std std-ref">Similarly to the bound for a type parameter</span></a>, defaults should be lazily evaluated, with the same scoping rules to avoid the unnecessary usage of quotes around them.</p> <p>This functionality was included in the initial draft of <a class="pep reference internal" href="../pep-0695/" title="PEP 695 – Type Parameter Syntax">PEP 695</a> but was removed due to scope creep.</p> <p>The following changes would be made to the grammar:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">type_param</span><span class="p">:</span> <span class="o">|</span> <span class="n">a</span><span class="o">=</span><span class="n">NAME</span> <span class="n">b</span><span class="o">=</span><span class="p">[</span><span class="n">type_param_bound</span><span class="p">]</span> <span class="n">d</span><span class="o">=</span><span class="p">[</span><span class="n">type_param_default</span><span class="p">]</span> <span class="o">|</span> <span class="n">a</span><span class="o">=</span><span class="n">NAME</span> <span class="n">c</span><span class="o">=</span><span class="p">[</span><span class="n">type_param_constraint</span><span class="p">]</span> <span class="n">d</span><span class="o">=</span><span class="p">[</span><span class="n">type_param_default</span><span class="p">]</span> <span class="o">|</span> <span class="s1">'*'</span> <span class="n">a</span><span class="o">=</span><span class="n">NAME</span> <span class="n">d</span><span class="o">=</span><span class="p">[</span><span class="n">type_param_default</span><span class="p">]</span> <span class="o">|</span> <span class="s1">'**'</span> <span class="n">a</span><span class="o">=</span><span class="n">NAME</span> <span class="n">d</span><span class="o">=</span><span class="p">[</span><span class="n">type_param_default</span><span class="p">]</span> <span class="n">type_param_default</span><span class="p">:</span> <span class="o">|</span> <span class="s1">'='</span> <span class="n">e</span><span class="o">=</span><span class="n">expression</span> <span class="o">|</span> <span class="s1">'='</span> <span class="n">e</span><span class="o">=</span><span class="n">starred_expression</span> </pre></div> </div> <p>The compiler would enforce that type parameters without defaults cannot follow type parameters with defaults and that <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code>s with defaults cannot immediately follow <code class="docutils literal notranslate"><span class="pre">TypeVarTuple</span></code>s.</p> </section> </section> <section id="rejected-alternatives"> <h2><a class="toc-backref" href="#rejected-alternatives" role="doc-backlink">Rejected Alternatives</a></h2> <section id="allowing-the-type-parameters-defaults-to-be-passed-to-type-new-s-kwargs"> <h3><a class="toc-backref" href="#allowing-the-type-parameters-defaults-to-be-passed-to-type-new-s-kwargs" role="doc-backlink">Allowing the Type Parameters Defaults to Be Passed to <code class="docutils literal notranslate"><span class="pre">type.__new__</span></code>’s <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code></a></h3> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">T</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"T"</span><span class="p">)</span> <span class="nd">@dataclass</span> <span class="k">class</span> <span class="nc">Box</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">T</span><span class="p">],</span> <span class="n">T</span><span class="o">=</span><span class="nb">int</span><span class="p">):</span> <span class="n">value</span><span class="p">:</span> <span class="n">T</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span> </pre></div> </div> <p>While this is much easier to read and follows a similar rationale to the <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code> <a class="reference external" href="https://github.com/python/typing/issues/813">unary syntax</a>, it would not be backwards compatible as <code class="docutils literal notranslate"><span class="pre">T</span></code> might already be passed to a metaclass/superclass or support classes that don’t subclass <code class="docutils literal notranslate"><span class="pre">Generic</span></code> at runtime.</p> <p>Ideally, if <a class="pep reference internal" href="../pep-0637/" title="PEP 637 – Support for indexing with keyword arguments">PEP 637</a> wasn’t rejected, the following would be acceptable:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">T</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"T"</span><span class="p">)</span> <span class="nd">@dataclass</span> <span class="k">class</span> <span class="nc">Box</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">T</span> <span class="o">=</span> <span class="nb">int</span><span class="p">]):</span> <span class="n">value</span><span class="p">:</span> <span class="n">T</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span> </pre></div> </div> </section> <section id="allowing-non-defaults-to-follow-defaults"> <h3><a class="toc-backref" href="#allowing-non-defaults-to-follow-defaults" role="doc-backlink">Allowing Non-defaults to Follow Defaults</a></h3> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">YieldT</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"YieldT"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">Any</span><span class="p">)</span> <span class="n">SendT</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"SendT"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">Any</span><span class="p">)</span> <span class="n">ReturnT</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"ReturnT"</span><span class="p">)</span> <span class="k">class</span> <span class="nc">Coroutine</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">YieldT</span><span class="p">,</span> <span class="n">SendT</span><span class="p">,</span> <span class="n">ReturnT</span><span class="p">]):</span> <span class="o">...</span> <span class="n">Coroutine</span><span class="p">[</span><span class="nb">int</span><span class="p">]</span> <span class="o">==</span> <span class="n">Coroutine</span><span class="p">[</span><span class="n">Any</span><span class="p">,</span> <span class="n">Any</span><span class="p">,</span> <span class="nb">int</span><span class="p">]</span> </pre></div> </div> <p>Allowing non-defaults to follow defaults would alleviate the issues with returning types like <code class="docutils literal notranslate"><span class="pre">Coroutine</span></code> from functions where the most used type argument is the last (the return). Allowing non-defaults to follow defaults is too confusing and potentially ambiguous, even if only the above two forms were valid. Changing the argument order now would also break a lot of codebases. This is also solvable in most cases using a <code class="docutils literal notranslate"><span class="pre">TypeAlias</span></code>.</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Coro</span><span class="p">:</span> <span class="n">TypeAlias</span> <span class="o">=</span> <span class="n">Coroutine</span><span class="p">[</span><span class="n">Any</span><span class="p">,</span> <span class="n">Any</span><span class="p">,</span> <span class="n">T</span><span class="p">]</span> <span class="n">Coro</span><span class="p">[</span><span class="nb">int</span><span class="p">]</span> <span class="o">==</span> <span class="n">Coroutine</span><span class="p">[</span><span class="n">Any</span><span class="p">,</span> <span class="n">Any</span><span class="p">,</span> <span class="nb">int</span><span class="p">]</span> </pre></div> </div> </section> <section id="having-default-implicitly-be-bound"> <h3><a class="toc-backref" href="#having-default-implicitly-be-bound" role="doc-backlink">Having <code class="docutils literal notranslate"><span class="pre">default</span></code> Implicitly Be <code class="docutils literal notranslate"><span class="pre">bound</span></code></a></h3> <p>In an earlier version of this PEP, the <code class="docutils literal notranslate"><span class="pre">default</span></code> was implicitly set to <code class="docutils literal notranslate"><span class="pre">bound</span></code> if no value was passed for <code class="docutils literal notranslate"><span class="pre">default</span></code>. This while convenient, could have a type parameter with no default follow a type parameter with a default. Consider:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">T</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"T"</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span> <span class="c1"># default is implicitly int</span> <span class="n">U</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"U"</span><span class="p">)</span> <span class="k">class</span> <span class="nc">Foo</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">T</span><span class="p">,</span> <span class="n">U</span><span class="p">]):</span> <span class="o">...</span> <span class="c1"># would expand to</span> <span class="n">T</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"T"</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="nb">int</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span> <span class="n">U</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">"U"</span><span class="p">)</span> <span class="k">class</span> <span class="nc">Foo</span><span class="p">(</span><span class="n">Generic</span><span class="p">[</span><span class="n">T</span><span class="p">,</span> <span class="n">U</span><span class="p">]):</span> <span class="o">...</span> </pre></div> </div> <p>This would have also been a breaking change for a small number of cases where the code relied on <code class="docutils literal notranslate"><span class="pre">Any</span></code> being the implicit default.</p> </section> <section id="allowing-type-parameters-with-defaults-to-be-used-in-function-signatures"> <h3><a class="toc-backref" href="#allowing-type-parameters-with-defaults-to-be-used-in-function-signatures" role="doc-backlink">Allowing Type Parameters With Defaults To Be Used in Function Signatures</a></h3> <p>A previous version of this PEP allowed <code class="docutils literal notranslate"><span class="pre">TypeVarLike</span></code>s with defaults to be used in function signatures. This was removed for the reasons described in <a class="reference internal" href="#id1">Function Defaults</a>. Hopefully, this can be added in the future if a way to get the runtime value of a type parameter is added.</p> </section> <section id="allowing-type-parameters-from-outer-scopes-in-default"> <h3><a class="toc-backref" href="#allowing-type-parameters-from-outer-scopes-in-default" role="doc-backlink">Allowing Type Parameters from Outer Scopes in <code class="docutils literal notranslate"><span class="pre">default</span></code></a></h3> <p>This was deemed too niche a feature to be worth the added complexity. If any cases arise where this is needed, it can be added in a future PEP.</p> </section> </section> <section id="acknowledgements"> <h2><a class="toc-backref" href="#acknowledgements" role="doc-backlink">Acknowledgements</a></h2> <p>Thanks to the following people for their feedback on the PEP:</p> <p>Eric Traut, Jelle Zijlstra, Joshua Butt, Danny Yamamoto, Kaylynn Morgan and Jakub Kuczys</p> </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-0696.rst">https://github.com/python/peps/blob/main/peps/pep-0696.rst</a></p> <p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0696.rst">2024-09-03 17:24:02 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="#default-ordering-and-subscription-rules">Default Ordering and Subscription Rules</a></li> <li><a class="reference internal" href="#paramspec-defaults"><code class="docutils literal notranslate"><span class="pre">ParamSpec</span></code> Defaults</a></li> <li><a class="reference internal" href="#typevartuple-defaults"><code class="docutils literal notranslate"><span class="pre">TypeVarTuple</span></code> Defaults</a></li> <li><a class="reference internal" href="#using-another-type-parameter-as-default">Using Another Type Parameter as <code class="docutils literal notranslate"><span class="pre">default</span></code></a><ul> <li><a class="reference internal" href="#scoping-rules">Scoping Rules</a></li> <li><a class="reference internal" href="#bound-rules">Bound Rules</a></li> <li><a class="reference internal" href="#constraint-rules">Constraint Rules</a></li> <li><a class="reference internal" href="#type-parameters-as-parameters-to-generics">Type Parameters as Parameters to Generics</a></li> <li><a class="reference internal" href="#specialisation-rules">Specialisation Rules</a></li> </ul> </li> <li><a class="reference internal" href="#generic-typealiases"><code class="docutils literal notranslate"><span class="pre">Generic</span></code> <code class="docutils literal notranslate"><span class="pre">TypeAlias</span></code>es</a></li> <li><a class="reference internal" href="#subclassing">Subclassing</a></li> <li><a class="reference internal" href="#using-bound-and-default">Using <code class="docutils literal notranslate"><span class="pre">bound</span></code> and <code class="docutils literal notranslate"><span class="pre">default</span></code></a></li> <li><a class="reference internal" href="#constraints">Constraints</a></li> <li><a class="reference internal" href="#function-defaults">Function Defaults</a></li> <li><a class="reference internal" href="#defaults-following-typevartuple">Defaults following <code class="docutils literal notranslate"><span class="pre">TypeVarTuple</span></code></a></li> <li><a class="reference internal" href="#subtyping">Subtyping</a></li> <li><a class="reference internal" href="#typevartuples-as-defaults"><code class="docutils literal notranslate"><span class="pre">TypeVarTuple</span></code>s as Defaults</a></li> </ul> </li> <li><a class="reference internal" href="#binding-rules">Binding rules</a></li> <li><a class="reference internal" href="#implementation">Implementation</a><ul> <li><a class="reference internal" href="#grammar-changes">Grammar changes</a></li> </ul> </li> <li><a class="reference internal" href="#rejected-alternatives">Rejected Alternatives</a><ul> <li><a class="reference internal" href="#allowing-the-type-parameters-defaults-to-be-passed-to-type-new-s-kwargs">Allowing the Type Parameters Defaults to Be Passed to <code class="docutils literal notranslate"><span class="pre">type.__new__</span></code>’s <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code></a></li> <li><a class="reference internal" href="#allowing-non-defaults-to-follow-defaults">Allowing Non-defaults to Follow Defaults</a></li> <li><a class="reference internal" href="#having-default-implicitly-be-bound">Having <code class="docutils literal notranslate"><span class="pre">default</span></code> Implicitly Be <code class="docutils literal notranslate"><span class="pre">bound</span></code></a></li> <li><a class="reference internal" href="#allowing-type-parameters-with-defaults-to-be-used-in-function-signatures">Allowing Type Parameters With Defaults To Be Used in Function Signatures</a></li> <li><a class="reference internal" href="#allowing-type-parameters-from-outer-scopes-in-default">Allowing Type Parameters from Outer Scopes in <code class="docutils literal notranslate"><span class="pre">default</span></code></a></li> </ul> </li> <li><a class="reference internal" href="#acknowledgements">Acknowledgements</a></li> <li><a class="reference internal" href="#copyright">Copyright</a></li> </ul> <br> <a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0696.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>