CINXE.COM
PEP 591 – Adding a final qualifier to typing | 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 591 – Adding a final qualifier to typing | peps.python.org</title> <link rel="shortcut icon" href="../_static/py.png"> <link rel="canonical" href="https://peps.python.org/pep-0591/"> <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 591 – Adding a final qualifier to typing | peps.python.org'> <meta property="og:description" content="This PEP proposes a “final” qualifier to be added to the typing module—in the form of a final decorator and a Final type annotation—to serve three related purposes:"> <meta property="og:type" content="website"> <meta property="og:url" content="https://peps.python.org/pep-0591/"> <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 proposes a “final” qualifier to be added to the typing module—in the form of a final decorator and a Final type annotation—to serve three related purposes:"> <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 591</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 591 – Adding a final qualifier to typing</h1> <dl class="rfc2822 field-list simple"> <dt class="field-odd">Author<span class="colon">:</span></dt> <dd class="field-odd">Michael J. Sullivan <sully at msully.net>, Ivan Levkivskyi <levkivskyi at gmail.com></dd> <dt class="field-even">BDFL-Delegate<span class="colon">:</span></dt> <dd class="field-even">Guido van Rossum <guido at python.org></dd> <dt class="field-odd">Discussions-To<span class="colon">:</span></dt> <dd class="field-odd"><a class="reference external" href="https://mail.python.org/archives/list/typing-sig@python.org/">Typing-SIG list</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">15-Mar-2019</dd> <dt class="field-even">Python-Version<span class="colon">:</span></dt> <dd class="field-even">3.8</dd> <dt class="field-odd">Post-History<span class="colon">:</span></dt> <dd class="field-odd"><p></p></dd> <dt class="field-even">Resolution<span class="colon">:</span></dt> <dd class="field-even"><a class="reference external" href="https://mail.python.org/archives/list/typing-sig@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><ul> <li><a class="reference internal" href="#the-final-decorator">The <code class="docutils literal notranslate"><span class="pre">final</span></code> decorator</a></li> <li><a class="reference internal" href="#the-final-annotation">The <code class="docutils literal notranslate"><span class="pre">Final</span></code> annotation</a></li> </ul> </li> <li><a class="reference internal" href="#specification">Specification</a><ul> <li><a class="reference internal" href="#id1">The <code class="docutils literal notranslate"><span class="pre">final</span></code> decorator</a></li> <li><a class="reference internal" href="#id2">The <code class="docutils literal notranslate"><span class="pre">Final</span></code> annotation</a><ul> <li><a class="reference internal" href="#syntax">Syntax</a></li> <li><a class="reference internal" href="#semantics-and-examples">Semantics and examples</a></li> </ul> </li> </ul> </li> <li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li> <li><a class="reference internal" href="#rejected-deferred-ideas">Rejected/deferred Ideas</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/qualifiers.html#at-final" title="(in typing)"><span>@final</span></a>/<a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.final" title="(in Python v3.13)"><code class="xref py py-func docutils literal notranslate"><span class="pre">@typing.final</span></code></a> and <a class="reference external" href="https://typing.readthedocs.io/en/latest/spec/qualifiers.html#uppercase-final" title="(in typing)"><span>Final</span></a>/<a class="reference external" href="https://docs.python.org/3/library/typing.html#typing.Final" title="(in Python v3.13)"><code class="xref py py-data docutils literal notranslate"><span class="pre">typing.Final</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>This PEP proposes a “final” qualifier to be added to the <code class="docutils literal notranslate"><span class="pre">typing</span></code> module—in the form of a <code class="docutils literal notranslate"><span class="pre">final</span></code> decorator and a <code class="docutils literal notranslate"><span class="pre">Final</span></code> type annotation—to serve three related purposes:</p> <ul class="simple"> <li>Declaring that a method should not be overridden</li> <li>Declaring that a class should not be subclassed</li> <li>Declaring that a variable or attribute should not be reassigned</li> </ul> </section> <section id="motivation"> <h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2> <section id="the-final-decorator"> <h3><a class="toc-backref" href="#the-final-decorator" role="doc-backlink">The <code class="docutils literal notranslate"><span class="pre">final</span></code> decorator</a></h3> <p>The current <code class="docutils literal notranslate"><span class="pre">typing</span></code> module lacks a way to restrict the use of inheritance or overriding at a typechecker level. This is a common feature in other object-oriented languages (such as Java), and is useful for reducing the potential space of behaviors of a class, easing reasoning.</p> <p>Some situations where a final class or method may be useful include:</p> <ul class="simple"> <li>A class wasn’t designed to be subclassed or a method wasn’t designed to be overridden. Perhaps it would not work as expected, or be error-prone.</li> <li>Subclassing or overriding would make code harder to understand or maintain. For example, you may want to prevent unnecessarily tight coupling between base classes and subclasses.</li> <li>You want to retain the freedom to arbitrarily change the class implementation in the future, and these changes might break subclasses.</li> </ul> </section> <section id="the-final-annotation"> <h3><a class="toc-backref" href="#the-final-annotation" role="doc-backlink">The <code class="docutils literal notranslate"><span class="pre">Final</span></code> annotation</a></h3> <p>The current <code class="docutils literal notranslate"><span class="pre">typing</span></code> module lacks a way to indicate that a variable will not be assigned to. This is a useful feature in several situations:</p> <ul class="simple"> <li>Preventing unintended modification of module and class level constants and documenting them as constants in a checkable way.</li> <li>Creating a read-only attribute that may not be overridden by subclasses. (<code class="docutils literal notranslate"><span class="pre">@property</span></code> can make an attribute read-only but does not prevent overriding)</li> <li>Allowing a name to be used in situations where ordinarily a literal is expected (for example as a field name for <code class="docutils literal notranslate"><span class="pre">NamedTuple</span></code>, a tuple of types passed to <code class="docutils literal notranslate"><span class="pre">isinstance</span></code>, or an argument to a function with arguments of <code class="docutils literal notranslate"><span class="pre">Literal</span></code> type (<a class="pep reference internal" href="../pep-0586/" title="PEP 586 – Literal Types">PEP 586</a>)).</li> </ul> </section> </section> <section id="specification"> <h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2> <section id="id1"> <h3><a class="toc-backref" href="#id1" role="doc-backlink">The <code class="docutils literal notranslate"><span class="pre">final</span></code> decorator</a></h3> <p>The <code class="docutils literal notranslate"><span class="pre">typing.final</span></code> decorator is used to restrict the use of inheritance and overriding.</p> <p>A type checker should prohibit any class decorated with <code class="docutils literal notranslate"><span class="pre">@final</span></code> from being subclassed and any method decorated with <code class="docutils literal notranslate"><span class="pre">@final</span></code> from being overridden in a subclass. The method decorator version may be used with all of instance methods, class methods, static methods, and properties.</p> <p>For example:</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">final</span> <span class="nd">@final</span> <span class="k">class</span> <span class="nc">Base</span><span class="p">:</span> <span class="o">...</span> <span class="k">class</span> <span class="nc">Derived</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span> <span class="c1"># Error: Cannot inherit from final class "Base"</span> <span class="o">...</span> </pre></div> </div> <p>and:</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">final</span> <span class="k">class</span> <span class="nc">Base</span><span class="p">:</span> <span class="nd">@final</span> <span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span> <span class="o">...</span> <span class="k">class</span> <span class="nc">Derived</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span> <span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span> <span class="c1"># Error: Cannot override final attribute "foo"</span> <span class="c1"># (previously declared in base class "Base")</span> <span class="o">...</span> </pre></div> </div> <p>For overloaded methods, <code class="docutils literal notranslate"><span class="pre">@final</span></code> should be placed on the implementation (or on the first overload, for stubs):</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">Any</span><span class="p">,</span> <span class="n">overload</span> <span class="k">class</span> <span class="nc">Base</span><span class="p">:</span> <span class="nd">@overload</span> <span class="k">def</span> <span class="nf">method</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span> <span class="o">...</span> <span class="nd">@overload</span> <span class="k">def</span> <span class="nf">method</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">arg</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-></span> <span class="nb">int</span><span class="p">:</span> <span class="o">...</span> <span class="nd">@final</span> <span class="k">def</span> <span class="nf">method</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">x</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span> <span class="o">...</span> </pre></div> </div> <p>It is an error to use <code class="docutils literal notranslate"><span class="pre">@final</span></code> on a non-method function.</p> </section> <section id="id2"> <h3><a class="toc-backref" href="#id2" role="doc-backlink">The <code class="docutils literal notranslate"><span class="pre">Final</span></code> annotation</a></h3> <p>The <code class="docutils literal notranslate"><span class="pre">typing.Final</span></code> type qualifier is used to indicate that a variable or attribute should not be reassigned, redefined, or overridden.</p> <section id="syntax"> <h4><a class="toc-backref" href="#syntax" role="doc-backlink">Syntax</a></h4> <p><code class="docutils literal notranslate"><span class="pre">Final</span></code> may be used in one of several forms:</p> <ul> <li>With an explicit type, using the syntax <code class="docutils literal notranslate"><span class="pre">Final[<type>]</span></code>. Example:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">ID</span><span class="p">:</span> <span class="n">Final</span><span class="p">[</span><span class="nb">float</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span> </pre></div> </div> </li> <li>With no type annotation. Example:<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">ID</span><span class="p">:</span> <span class="n">Final</span> <span class="o">=</span> <span class="mi">1</span> </pre></div> </div> <p>The typechecker should apply its usual type inference mechanisms to determine the type of <code class="docutils literal notranslate"><span class="pre">ID</span></code> (here, likely, <code class="docutils literal notranslate"><span class="pre">int</span></code>). Note that unlike for generic classes this is <em>not</em> the same as <code class="docutils literal notranslate"><span class="pre">Final[Any]</span></code>.</p> </li> <li>In class bodies and stub files you can omit the right hand side and just write <code class="docutils literal notranslate"><span class="pre">ID:</span> <span class="pre">Final[float]</span></code>. If the right hand side is omitted, there must be an explicit type argument to <code class="docutils literal notranslate"><span class="pre">Final</span></code>.</li> <li>Finally, as <code class="docutils literal notranslate"><span class="pre">self.id:</span> <span class="pre">Final</span> <span class="pre">=</span> <span class="pre">1</span></code> (also optionally with a type in square brackets). This is allowed <em>only</em> in <code class="docutils literal notranslate"><span class="pre">__init__</span></code> methods, so that the final instance attribute is assigned only once when an instance is created.</li> </ul> </section> <section id="semantics-and-examples"> <h4><a class="toc-backref" href="#semantics-and-examples" role="doc-backlink">Semantics and examples</a></h4> <p>The two main rules for defining a final name are:</p> <ul class="simple"> <li>There can be <em>at most one</em> final declaration per module or class for a given attribute. There can’t be separate class-level and instance-level constants with the same name.</li> <li>There must be <em>exactly one</em> assignment to a final name.</li> </ul> <p>This means a type checker should prevent further assignments to final names in type-checked code:</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">Final</span> <span class="n">RATE</span><span class="p">:</span> <span class="n">Final</span> <span class="o">=</span> <span class="mi">3000</span> <span class="k">class</span> <span class="nc">Base</span><span class="p">:</span> <span class="n">DEFAULT_ID</span><span class="p">:</span> <span class="n">Final</span> <span class="o">=</span> <span class="mi">0</span> <span class="n">RATE</span> <span class="o">=</span> <span class="mi">300</span> <span class="c1"># Error: can't assign to final attribute</span> <span class="n">Base</span><span class="o">.</span><span class="n">DEFAULT_ID</span> <span class="o">=</span> <span class="mi">1</span> <span class="c1"># Error: can't override a final attribute</span> </pre></div> </div> <p>Note that a type checker need not allow <code class="docutils literal notranslate"><span class="pre">Final</span></code> declarations inside loops since the runtime will see multiple assignments to the same variable in subsequent iterations.</p> <p>Additionally, a type checker should prevent final attributes from being overridden in a subclass:</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">Final</span> <span class="k">class</span> <span class="nc">Window</span><span class="p">:</span> <span class="n">BORDER_WIDTH</span><span class="p">:</span> <span class="n">Final</span> <span class="o">=</span> <span class="mf">2.5</span> <span class="o">...</span> <span class="k">class</span> <span class="nc">ListView</span><span class="p">(</span><span class="n">Window</span><span class="p">):</span> <span class="n">BORDER_WIDTH</span> <span class="o">=</span> <span class="mi">3</span> <span class="c1"># Error: can't override a final attribute</span> </pre></div> </div> <p>A final attribute declared in a class body without an initializer must be initialized in the <code class="docutils literal notranslate"><span class="pre">__init__</span></code> method (except in stub files):</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">ImmutablePoint</span><span class="p">:</span> <span class="n">x</span><span class="p">:</span> <span class="n">Final</span><span class="p">[</span><span class="nb">int</span><span class="p">]</span> <span class="n">y</span><span class="p">:</span> <span class="n">Final</span><span class="p">[</span><span class="nb">int</span><span class="p">]</span> <span class="c1"># Error: final attribute without an initializer</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="o">-></span> <span class="kc">None</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="mi">1</span> <span class="c1"># Good</span> </pre></div> </div> <p>Type checkers should infer a final attribute that is initialized in a class body as being a class variable. Variables should not be annotated with both <code class="docutils literal notranslate"><span class="pre">ClassVar</span></code> and <code class="docutils literal notranslate"><span class="pre">Final</span></code>.</p> <p><code class="docutils literal notranslate"><span class="pre">Final</span></code> may only be used as the outermost type in assignments or variable annotations. Using it in any other position is an error. In particular, <code class="docutils literal notranslate"><span class="pre">Final</span></code> can’t be used in annotations for function arguments:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">x</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">Final</span><span class="p">[</span><span class="nb">int</span><span class="p">]]</span> <span class="o">=</span> <span class="p">[]</span> <span class="c1"># Error!</span> <span class="k">def</span> <span class="nf">fun</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="n">Final</span><span class="p">[</span><span class="n">List</span><span class="p">[</span><span class="nb">int</span><span class="p">]])</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span> <span class="c1"># Error!</span> <span class="o">...</span> </pre></div> </div> <p>Note that declaring a name as final only guarantees that the name will not be re-bound to another value, but does not make the value immutable. Immutable ABCs and containers may be used in combination with <code class="docutils literal notranslate"><span class="pre">Final</span></code> to prevent mutating such values:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">x</span><span class="p">:</span> <span class="n">Final</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'a'</span><span class="p">,</span> <span class="s1">'b'</span><span class="p">]</span> <span class="n">x</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">'c'</span><span class="p">)</span> <span class="c1"># OK</span> <span class="n">y</span><span class="p">:</span> <span class="n">Final</span><span class="p">[</span><span class="n">Sequence</span><span class="p">[</span><span class="nb">str</span><span class="p">]]</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'a'</span><span class="p">,</span> <span class="s1">'b'</span><span class="p">]</span> <span class="n">y</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">'x'</span><span class="p">)</span> <span class="c1"># Error: "Sequence[str]" has no attribute "append"</span> <span class="n">z</span><span class="p">:</span> <span class="n">Final</span> <span class="o">=</span> <span class="p">(</span><span class="s1">'a'</span><span class="p">,</span> <span class="s1">'b'</span><span class="p">)</span> <span class="c1"># Also works</span> </pre></div> </div> <p>Type checkers should treat uses of a final name that was initialized with a literal as if it was replaced by the literal. For example, the following should be allowed:</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">NamedTuple</span><span class="p">,</span> <span class="n">Final</span> <span class="n">X</span><span class="p">:</span> <span class="n">Final</span> <span class="o">=</span> <span class="s2">"x"</span> <span class="n">Y</span><span class="p">:</span> <span class="n">Final</span> <span class="o">=</span> <span class="s2">"y"</span> <span class="n">N</span> <span class="o">=</span> <span class="n">NamedTuple</span><span class="p">(</span><span class="s2">"N"</span><span class="p">,</span> <span class="p">[(</span><span class="n">X</span><span class="p">,</span> <span class="nb">int</span><span class="p">),</span> <span class="p">(</span><span class="n">Y</span><span class="p">,</span> <span class="nb">int</span><span class="p">)])</span> </pre></div> </div> </section> </section> </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="id3">[1]</a> type checker supports <code class="docutils literal notranslate"><span class="pre">Final</span></code> and <code class="docutils literal notranslate"><span class="pre">final</span></code>. 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="id4">[2]</a> module.</p> </section> <section id="rejected-deferred-ideas"> <h2><a class="toc-backref" href="#rejected-deferred-ideas" role="doc-backlink">Rejected/deferred Ideas</a></h2> <p>The name <code class="docutils literal notranslate"><span class="pre">Const</span></code> was also considered as the name for the <code class="docutils literal notranslate"><span class="pre">Final</span></code> type annotation. The name <code class="docutils literal notranslate"><span class="pre">Final</span></code> was chosen instead because the concepts are related and it seemed best to be consistent between them.</p> <p>We considered using a single name <code class="docutils literal notranslate"><span class="pre">Final</span></code> instead of introducing <code class="docutils literal notranslate"><span class="pre">final</span></code> as well, but <code class="docutils literal notranslate"><span class="pre">@Final</span></code> just looked too weird to us.</p> <p>A related feature to final classes would be Scala-style sealed classes, where a class is allowed to be inherited only by classes defined in the same module. Sealed classes seem most useful in combination with pattern matching, so it does not seem to justify the complexity in our case. This could be revisited in the future.</p> <p>It would be possible to have the <code class="docutils literal notranslate"><span class="pre">@final</span></code> decorator on classes dynamically prevent subclassing at runtime. Nothing else in <code class="docutils literal notranslate"><span class="pre">typing</span></code> does any runtime enforcement, though, so <code class="docutils literal notranslate"><span class="pre">final</span></code> will not either. A workaround for when both runtime enforcement and static checking is desired is to use this idiom (possibly in a support module):</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="n">typing</span><span class="o">.</span><span class="n">TYPE_CHECKING</span><span class="p">:</span> <span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">final</span> <span class="k">else</span><span class="p">:</span> <span class="kn">from</span> <span class="nn">runtime_final</span> <span class="kn">import</span> <span class="n">final</span> </pre></div> </div> </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="mypy" role="doc-footnote"> <dt class="label" id="mypy">[<a href="#id3">1</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="#id4">2</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> </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-0591.rst">https://github.com/python/peps/blob/main/peps/pep-0591.rst</a></p> <p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0591.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><ul> <li><a class="reference internal" href="#the-final-decorator">The <code class="docutils literal notranslate"><span class="pre">final</span></code> decorator</a></li> <li><a class="reference internal" href="#the-final-annotation">The <code class="docutils literal notranslate"><span class="pre">Final</span></code> annotation</a></li> </ul> </li> <li><a class="reference internal" href="#specification">Specification</a><ul> <li><a class="reference internal" href="#id1">The <code class="docutils literal notranslate"><span class="pre">final</span></code> decorator</a></li> <li><a class="reference internal" href="#id2">The <code class="docutils literal notranslate"><span class="pre">Final</span></code> annotation</a><ul> <li><a class="reference internal" href="#syntax">Syntax</a></li> <li><a class="reference internal" href="#semantics-and-examples">Semantics and examples</a></li> </ul> </li> </ul> </li> <li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li> <li><a class="reference internal" href="#rejected-deferred-ideas">Rejected/deferred Ideas</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-0591.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>