peps/pep-0673/index.html

853 lines
89 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!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 673 Self Type | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-0673/">
<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 673 Self Type | peps.python.org'>
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-0673/">
<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="Python Enhancement Proposals (PEPs)">
<meta name="theme-color" content="#3776ab">
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all">
<title>Following system colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="9"></circle>
<path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path>
</svg>
</symbol>
<symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all">
<title>Selected dark colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path>
</svg>
</symbol>
<symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all">
<title>Selected light colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
</symbol>
</svg>
<script>
document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto"
</script>
<section id="pep-page-section">
<header>
<h1>Python Enhancement Proposals</h1>
<ul class="breadcrumbs">
<li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> &raquo; </li>
<li><a href="../pep-0000/">PEP Index</a> &raquo; </li>
<li>PEP 673</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 673 Self Type</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Pradeep Kumar Srinivasan &lt;gohanpra&#32;&#97;t&#32;gmail.com&gt;,
James Hilton-Balfe &lt;gobot1234yt&#32;&#97;t&#32;gmail.com&gt;</dd>
<dt class="field-even">Sponsor<span class="colon">:</span></dt>
<dd class="field-even">Jelle Zijlstra &lt;jelle.zijlstra&#32;&#97;t&#32;gmail.com&gt;</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&#64;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">10-Nov-2021</dd>
<dt class="field-even">Python-Version<span class="colon">:</span></dt>
<dd class="field-even">3.11</dd>
<dt class="field-odd">Post-History<span class="colon">:</span></dt>
<dd class="field-odd">17-Nov-2021</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/python-dev&#64;python.org/thread/J7BWL5KWOPQQK5KFWKENVLXW6UGSPTGI/">Python-Dev thread</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="#usage-statistics">Usage statistics</a></li>
</ul>
</li>
<li><a class="reference internal" href="#specification">Specification</a><ul>
<li><a class="reference internal" href="#use-in-method-signatures">Use in Method Signatures</a></li>
<li><a class="reference internal" href="#use-in-classmethod-signatures">Use in Classmethod Signatures</a></li>
<li><a class="reference internal" href="#use-in-parameter-types">Use in Parameter Types</a></li>
<li><a class="reference internal" href="#use-in-attribute-annotations">Use in Attribute Annotations</a></li>
<li><a class="reference internal" href="#use-in-generic-classes">Use in Generic Classes</a></li>
<li><a class="reference internal" href="#use-in-protocols">Use in Protocols</a></li>
</ul>
</li>
<li><a class="reference internal" href="#valid-locations-for-self">Valid Locations for <code class="docutils literal notranslate"><span class="pre">Self</span></code></a></li>
<li><a class="reference internal" href="#runtime-behavior">Runtime behavior</a></li>
<li><a class="reference internal" href="#rejected-alternatives">Rejected Alternatives</a><ul>
<li><a class="reference internal" href="#allow-the-type-checker-to-infer-the-return-type">Allow the Type Checker to Infer the Return Type</a></li>
</ul>
</li>
<li><a class="reference internal" href="#reference-implementations">Reference Implementations</a></li>
<li><a class="reference internal" href="#resources">Resources</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. The up-to-date, canonical spec, <a class="reference external" href="https://typing.readthedocs.io/en/latest/spec/generics.html#self" title="(in typing)"><span>Self</span></a>, is maintained on the <a class="reference external" href="https://typing.readthedocs.io/en/latest/spec/">typing specs site</a>.</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.</p>
</div>
<section id="abstract">
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
<p>This PEP introduces a simple and intuitive way to annotate methods that return
an instance of their class. This behaves the same as the <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code>-based
approach specified in <a class="pep reference internal" href="../pep-0484/" title="PEP 484 Type Hints">PEP 484</a>
but is more concise and easier to follow.</p>
</section>
<section id="motivation">
<h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2>
<p>A common use case is to write a method that returns an instance of the same
class, usually by returning <code class="docutils literal notranslate"><span class="pre">self</span></code>.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Shape</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">set_scale</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">scale</span><span class="p">:</span> <span class="nb">float</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">scale</span> <span class="o">=</span> <span class="n">scale</span>
<span class="k">return</span> <span class="bp">self</span>
<span class="n">Shape</span><span class="p">()</span><span class="o">.</span><span class="n">set_scale</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span> <span class="c1"># =&gt; should be Shape</span>
</pre></div>
</div>
<p>One way to denote the return type is to specify it as the current class, say,
<code class="docutils literal notranslate"><span class="pre">Shape</span></code>. Using the method makes the type checker infer the type <code class="docutils literal notranslate"><span class="pre">Shape</span></code>,
as expected.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Shape</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">set_scale</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">scale</span><span class="p">:</span> <span class="nb">float</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Shape</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">scale</span> <span class="o">=</span> <span class="n">scale</span>
<span class="k">return</span> <span class="bp">self</span>
<span class="n">Shape</span><span class="p">()</span><span class="o">.</span><span class="n">set_scale</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span> <span class="c1"># =&gt; Shape</span>
</pre></div>
</div>
<p>However, when we call <code class="docutils literal notranslate"><span class="pre">set_scale</span></code> on a subclass of <code class="docutils literal notranslate"><span class="pre">Shape</span></code>, the type
checker still infers the return type to be <code class="docutils literal notranslate"><span class="pre">Shape</span></code>. This is problematic in
situations such as the one shown below, where the type checker will return an
error because we are trying to use attributes or methods not present on the
base class.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Circle</span><span class="p">(</span><span class="n">Shape</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">set_radius</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">r</span><span class="p">:</span> <span class="nb">float</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Circle</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">radius</span> <span class="o">=</span> <span class="n">r</span>
<span class="k">return</span> <span class="bp">self</span>
<span class="n">Circle</span><span class="p">()</span><span class="o">.</span><span class="n">set_scale</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span> <span class="c1"># *Shape*, not Circle</span>
<span class="n">Circle</span><span class="p">()</span><span class="o">.</span><span class="n">set_scale</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span><span class="o">.</span><span class="n">set_radius</span><span class="p">(</span><span class="mf">2.7</span><span class="p">)</span>
<span class="c1"># =&gt; Error: Shape has no attribute set_radius</span>
</pre></div>
</div>
<p>The present workaround for such instances is to define a <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code> with the
base class as the bound and use it as the annotation for the <code class="docutils literal notranslate"><span class="pre">self</span></code>
parameter and the return type:</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">TypeVar</span>
<span class="n">TShape</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">&quot;TShape&quot;</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="s2">&quot;Shape&quot;</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Shape</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">set_scale</span><span class="p">(</span><span class="bp">self</span><span class="p">:</span> <span class="n">TShape</span><span class="p">,</span> <span class="n">scale</span><span class="p">:</span> <span class="nb">float</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">TShape</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">scale</span> <span class="o">=</span> <span class="n">scale</span>
<span class="k">return</span> <span class="bp">self</span>
<span class="k">class</span> <span class="nc">Circle</span><span class="p">(</span><span class="n">Shape</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">set_radius</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">radius</span><span class="p">:</span> <span class="nb">float</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Circle</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">radius</span> <span class="o">=</span> <span class="n">radius</span>
<span class="k">return</span> <span class="bp">self</span>
<span class="n">Circle</span><span class="p">()</span><span class="o">.</span><span class="n">set_scale</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span><span class="o">.</span><span class="n">set_radius</span><span class="p">(</span><span class="mf">2.7</span><span class="p">)</span> <span class="c1"># =&gt; Circle</span>
</pre></div>
</div>
<p>Unfortunately, this is verbose and unintuitive. Because <code class="docutils literal notranslate"><span class="pre">self</span></code> is usually
not explicitly annotated, the above solution doesnt immediately come to mind,
and even if it does, it is very easy to go wrong by forgetting either the
bound on the <code class="docutils literal notranslate"><span class="pre">TypeVar(bound=&quot;Shape&quot;)</span></code> or the annotation for <code class="docutils literal notranslate"><span class="pre">self</span></code>.</p>
<p>This difficulty means that users often give up and either use fallback types
like <code class="docutils literal notranslate"><span class="pre">Any</span></code> or just omit the type annotation completely, both of which make
the code less safe.</p>
<p>We propose a more intuitive and succinct way of expressing the above
intention. We introduce a special form <code class="docutils literal notranslate"><span class="pre">Self</span></code> that stands for a type
variable bound to the encapsulating class. For situations such as the one
above, the user simply has to annotate the return type as <code class="docutils literal notranslate"><span class="pre">Self</span></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">Self</span>
<span class="k">class</span> <span class="nc">Shape</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">set_scale</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">scale</span><span class="p">:</span> <span class="nb">float</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Self</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">scale</span> <span class="o">=</span> <span class="n">scale</span>
<span class="k">return</span> <span class="bp">self</span>
<span class="k">class</span> <span class="nc">Circle</span><span class="p">(</span><span class="n">Shape</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">set_radius</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">radius</span><span class="p">:</span> <span class="nb">float</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Self</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">radius</span> <span class="o">=</span> <span class="n">radius</span>
<span class="k">return</span> <span class="bp">self</span>
</pre></div>
</div>
<p>By annotating the return type as <code class="docutils literal notranslate"><span class="pre">Self</span></code>, we no longer have to declare a
<code class="docutils literal notranslate"><span class="pre">TypeVar</span></code> with an explicit bound on the base class. The return type <code class="docutils literal notranslate"><span class="pre">Self</span></code>
mirrors the fact that the function returns <code class="docutils literal notranslate"><span class="pre">self</span></code> and is easier to
understand.</p>
<p>As in the above example, the type checker will correctly infer the type of
<code class="docutils literal notranslate"><span class="pre">Circle().set_scale(0.5)</span></code> to be <code class="docutils literal notranslate"><span class="pre">Circle</span></code>, as expected.</p>
<section id="usage-statistics">
<h3><a class="toc-backref" href="#usage-statistics" role="doc-backlink">Usage statistics</a></h3>
<p>We <a class="reference external" href="https://github.com/pradeep90/annotation_collector/#self-type-stats">analyzed</a> popular
open-source projects and found that patterns like the above were used about
<strong>40%</strong> as often as popular types like <code class="docutils literal notranslate"><span class="pre">dict</span></code> or <code class="docutils literal notranslate"><span class="pre">Callable</span></code>. For example,
in typeshed alone, such “Self” types are used 523 times, compared to 1286 uses
of <code class="docutils literal notranslate"><span class="pre">dict</span></code> and 1314 uses of <code class="docutils literal notranslate"><span class="pre">Callable</span></code> <a class="reference external" href="https://github.com/pradeep90/annotation_collector/#overall-stats-in-typeshed">as of October 2021</a>.
This suggests that a <code class="docutils literal notranslate"><span class="pre">Self</span></code> type will be used quite often and users will
benefit a lot from the simpler approach above.</p>
<p>Users of Python types have also frequently requested this feature,
both on the <a class="reference external" href="https://docs.google.com/document/d/1ujuSMXDmSIOJpiZyV7mvBEC8P-y55AgSzXcvhrZciuI/edit?disco=AAAARP_cNdc">proposal doc</a>
and on <a class="reference external" href="https://github.com/python/mypy/issues/11871">GitHub</a>.</p>
</section>
</section>
<section id="specification">
<h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2>
<section id="use-in-method-signatures">
<h3><a class="toc-backref" href="#use-in-method-signatures" role="doc-backlink">Use in Method Signatures</a></h3>
<p><code class="docutils literal notranslate"><span class="pre">Self</span></code> used in the signature of a method is treated as if it were a
<code class="docutils literal notranslate"><span class="pre">TypeVar</span></code> bound to the class.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Self</span>
<span class="k">class</span> <span class="nc">Shape</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">set_scale</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">scale</span><span class="p">:</span> <span class="nb">float</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Self</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">scale</span> <span class="o">=</span> <span class="n">scale</span>
<span class="k">return</span> <span class="bp">self</span>
</pre></div>
</div>
<p>is treated equivalently to:</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">TypeVar</span>
<span class="n">SelfShape</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">&quot;SelfShape&quot;</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="s2">&quot;Shape&quot;</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Shape</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">set_scale</span><span class="p">(</span><span class="bp">self</span><span class="p">:</span> <span class="n">SelfShape</span><span class="p">,</span> <span class="n">scale</span><span class="p">:</span> <span class="nb">float</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">SelfShape</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">scale</span> <span class="o">=</span> <span class="n">scale</span>
<span class="k">return</span> <span class="bp">self</span>
</pre></div>
</div>
<p>This works the same for a subclass too:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Circle</span><span class="p">(</span><span class="n">Shape</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">set_radius</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">radius</span><span class="p">:</span> <span class="nb">float</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Self</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">radius</span> <span class="o">=</span> <span class="n">radius</span>
<span class="k">return</span> <span class="bp">self</span>
</pre></div>
</div>
<p>which is treated equivalently to:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">SelfCircle</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">&quot;SelfCircle&quot;</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="s2">&quot;Circle&quot;</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Circle</span><span class="p">(</span><span class="n">Shape</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">set_radius</span><span class="p">(</span><span class="bp">self</span><span class="p">:</span> <span class="n">SelfCircle</span><span class="p">,</span> <span class="n">radius</span><span class="p">:</span> <span class="nb">float</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">SelfCircle</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">radius</span> <span class="o">=</span> <span class="n">radius</span>
<span class="k">return</span> <span class="bp">self</span>
</pre></div>
</div>
<p>One implementation strategy is to simply desugar the former to the latter in a
preprocessing step. If a method uses <code class="docutils literal notranslate"><span class="pre">Self</span></code> in its signature, the type of
<code class="docutils literal notranslate"><span class="pre">self</span></code> within a method will be <code class="docutils literal notranslate"><span class="pre">Self</span></code>. In other cases, the type of
<code class="docutils literal notranslate"><span class="pre">self</span></code> will remain the enclosing class.</p>
</section>
<section id="use-in-classmethod-signatures">
<h3><a class="toc-backref" href="#use-in-classmethod-signatures" role="doc-backlink">Use in Classmethod Signatures</a></h3>
<p>The <code class="docutils literal notranslate"><span class="pre">Self</span></code> type annotation is also useful for classmethods that return
an instance of the class that they operate on. For example, <code class="docutils literal notranslate"><span class="pre">from_config</span></code> in
the following snippet builds a <code class="docutils literal notranslate"><span class="pre">Shape</span></code> object from a given <code class="docutils literal notranslate"><span class="pre">config</span></code>.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Shape</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">scale</span><span class="p">:</span> <span class="nb">float</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span> <span class="o">...</span>
<span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">from_config</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">config</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">float</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">Shape</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">cls</span><span class="p">(</span><span class="n">config</span><span class="p">[</span><span class="s2">&quot;scale&quot;</span><span class="p">])</span>
</pre></div>
</div>
<p>However, this means that <code class="docutils literal notranslate"><span class="pre">Circle.from_config(...)</span></code> is inferred to return a
value of type <code class="docutils literal notranslate"><span class="pre">Shape</span></code>, when in fact it should be <code class="docutils literal notranslate"><span class="pre">Circle</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Circle</span><span class="p">(</span><span class="n">Shape</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">circumference</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">float</span><span class="p">:</span> <span class="o">...</span>
<span class="n">shape</span> <span class="o">=</span> <span class="n">Shape</span><span class="o">.</span><span class="n">from_config</span><span class="p">({</span><span class="s2">&quot;scale&quot;</span><span class="p">:</span> <span class="mf">7.0</span><span class="p">})</span>
<span class="c1"># =&gt; Shape</span>
<span class="n">circle</span> <span class="o">=</span> <span class="n">Circle</span><span class="o">.</span><span class="n">from_config</span><span class="p">({</span><span class="s2">&quot;scale&quot;</span><span class="p">:</span> <span class="mf">7.0</span><span class="p">})</span>
<span class="c1"># =&gt; *Shape*, not Circle</span>
<span class="n">circle</span><span class="o">.</span><span class="n">circumference</span><span class="p">()</span>
<span class="c1"># Error: `Shape` has no attribute `circumference`</span>
</pre></div>
</div>
<p>The current workaround for this is unintuitive and error-prone:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Self</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">&quot;Self&quot;</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="s2">&quot;Shape&quot;</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Shape</span><span class="p">:</span>
<span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">from_config</span><span class="p">(</span>
<span class="bp">cls</span><span class="p">:</span> <span class="nb">type</span><span class="p">[</span><span class="n">Self</span><span class="p">],</span> <span class="n">config</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">float</span><span class="p">]</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Self</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">cls</span><span class="p">(</span><span class="n">config</span><span class="p">[</span><span class="s2">&quot;scale&quot;</span><span class="p">])</span>
</pre></div>
</div>
<p>We propose using <code class="docutils literal notranslate"><span class="pre">Self</span></code> directly:</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">Self</span>
<span class="k">class</span> <span class="nc">Shape</span><span class="p">:</span>
<span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">from_config</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">config</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">float</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">Self</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">cls</span><span class="p">(</span><span class="n">config</span><span class="p">[</span><span class="s2">&quot;scale&quot;</span><span class="p">])</span>
</pre></div>
</div>
<p>This avoids the complicated <code class="docutils literal notranslate"><span class="pre">cls:</span> <span class="pre">type[Self]</span></code> annotation and the <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code>
declaration with a <code class="docutils literal notranslate"><span class="pre">bound</span></code>. Once again, the latter code behaves equivalently
to the former code.</p>
</section>
<section id="use-in-parameter-types">
<h3><a class="toc-backref" href="#use-in-parameter-types" role="doc-backlink">Use in Parameter Types</a></h3>
<p>Another use for <code class="docutils literal notranslate"><span class="pre">Self</span></code> is to annotate parameters that expect instances of
the current class:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Self</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">&quot;Self&quot;</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="s2">&quot;Shape&quot;</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Shape</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">difference</span><span class="p">(</span><span class="bp">self</span><span class="p">:</span> <span class="n">Self</span><span class="p">,</span> <span class="n">other</span><span class="p">:</span> <span class="n">Self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">float</span><span class="p">:</span> <span class="o">...</span>
<span class="k">def</span> <span class="nf">apply</span><span class="p">(</span><span class="bp">self</span><span class="p">:</span> <span class="n">Self</span><span class="p">,</span> <span class="n">f</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[[</span><span class="n">Self</span><span class="p">],</span> <span class="kc">None</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span> <span class="o">...</span>
</pre></div>
</div>
<p>We propose using <code class="docutils literal notranslate"><span class="pre">Self</span></code> directly to achieve the same behavior:</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">Self</span>
<span class="k">class</span> <span class="nc">Shape</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">difference</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">:</span> <span class="n">Self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">float</span><span class="p">:</span> <span class="o">...</span>
<span class="k">def</span> <span class="nf">apply</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">f</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[[</span><span class="n">Self</span><span class="p">],</span> <span class="kc">None</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span> <span class="o">...</span>
</pre></div>
</div>
<p>Note that specifying <code class="docutils literal notranslate"><span class="pre">self:</span> <span class="pre">Self</span></code> is harmless, so some users may find it
more readable to write the above as:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Shape</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">difference</span><span class="p">(</span><span class="bp">self</span><span class="p">:</span> <span class="n">Self</span><span class="p">,</span> <span class="n">other</span><span class="p">:</span> <span class="n">Self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">float</span><span class="p">:</span> <span class="o">...</span>
</pre></div>
</div>
</section>
<section id="use-in-attribute-annotations">
<h3><a class="toc-backref" href="#use-in-attribute-annotations" role="doc-backlink">Use in Attribute Annotations</a></h3>
<p>Another use for <code class="docutils literal notranslate"><span class="pre">Self</span></code> is to annotate attributes. One example is where we
have a <code class="docutils literal notranslate"><span class="pre">LinkedList</span></code> whose elements must be subclasses of the current class.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">dataclasses</span> <span class="kn">import</span> <span class="n">dataclass</span>
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Generic</span><span class="p">,</span> <span class="n">TypeVar</span>
<span class="n">T</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">&quot;T&quot;</span><span class="p">)</span>
<span class="nd">@dataclass</span>
<span class="k">class</span> <span class="nc">LinkedList</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="nb">next</span><span class="p">:</span> <span class="n">LinkedList</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="o">=</span> <span class="kc">None</span>
<span class="c1"># OK</span>
<span class="n">LinkedList</span><span class="p">[</span><span class="nb">int</span><span class="p">](</span><span class="n">value</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="nb">next</span><span class="o">=</span><span class="n">LinkedList</span><span class="p">[</span><span class="nb">int</span><span class="p">](</span><span class="n">value</span><span class="o">=</span><span class="mi">2</span><span class="p">))</span>
<span class="c1"># Not OK</span>
<span class="n">LinkedList</span><span class="p">[</span><span class="nb">int</span><span class="p">](</span><span class="n">value</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="nb">next</span><span class="o">=</span><span class="n">LinkedList</span><span class="p">[</span><span class="nb">str</span><span class="p">](</span><span class="n">value</span><span class="o">=</span><span class="s2">&quot;hello&quot;</span><span class="p">))</span>
</pre></div>
</div>
<p>However, annotating the <code class="docutils literal notranslate"><span class="pre">next</span></code> attribute as <code class="docutils literal notranslate"><span class="pre">LinkedList[T]</span></code> allows invalid
constructions with subclasses:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@dataclass</span>
<span class="k">class</span> <span class="nc">OrdinalLinkedList</span><span class="p">(</span><span class="n">LinkedList</span><span class="p">[</span><span class="nb">int</span><span class="p">]):</span>
<span class="k">def</span> <span class="nf">ordinal_value</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">return</span> <span class="n">as_ordinal</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">value</span><span class="p">)</span>
<span class="c1"># Should not be OK because LinkedList[int] is not a subclass of</span>
<span class="c1"># OrdinalLinkedList, # but the type checker allows it.</span>
<span class="n">xs</span> <span class="o">=</span> <span class="n">OrdinalLinkedList</span><span class="p">(</span><span class="n">value</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="nb">next</span><span class="o">=</span><span class="n">LinkedList</span><span class="p">[</span><span class="nb">int</span><span class="p">](</span><span class="n">value</span><span class="o">=</span><span class="mi">2</span><span class="p">))</span>
<span class="k">if</span> <span class="n">xs</span><span class="o">.</span><span class="n">next</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="n">xs</span><span class="o">.</span><span class="n">next</span><span class="o">.</span><span class="n">ordinal_value</span><span class="p">())</span> <span class="c1"># Runtime Error.</span>
</pre></div>
</div>
<p>We propose expressing this constraint using <code class="docutils literal notranslate"><span class="pre">next:</span> <span class="pre">Self</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="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Self</span>
<span class="nd">@dataclass</span>
<span class="k">class</span> <span class="nc">LinkedList</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="nb">next</span><span class="p">:</span> <span class="n">Self</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span>
<span class="nd">@dataclass</span>
<span class="k">class</span> <span class="nc">OrdinalLinkedList</span><span class="p">(</span><span class="n">LinkedList</span><span class="p">[</span><span class="nb">int</span><span class="p">]):</span>
<span class="k">def</span> <span class="nf">ordinal_value</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">return</span> <span class="n">as_ordinal</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">value</span><span class="p">)</span>
<span class="n">xs</span> <span class="o">=</span> <span class="n">OrdinalLinkedList</span><span class="p">(</span><span class="n">value</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="nb">next</span><span class="o">=</span><span class="n">LinkedList</span><span class="p">[</span><span class="nb">int</span><span class="p">](</span><span class="n">value</span><span class="o">=</span><span class="mi">2</span><span class="p">))</span>
<span class="c1"># Type error: Expected OrdinalLinkedList, got LinkedList[int].</span>
<span class="k">if</span> <span class="n">xs</span><span class="o">.</span><span class="n">next</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">xs</span><span class="o">.</span><span class="n">next</span> <span class="o">=</span> <span class="n">OrdinalLinkedList</span><span class="p">(</span><span class="n">value</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="nb">next</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span> <span class="c1"># OK</span>
<span class="n">xs</span><span class="o">.</span><span class="n">next</span> <span class="o">=</span> <span class="n">LinkedList</span><span class="p">[</span><span class="nb">int</span><span class="p">](</span><span class="n">value</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="nb">next</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span> <span class="c1"># Not OK</span>
</pre></div>
</div>
<p>The code above is semantically equivalent to treating each attribute
containing a <code class="docutils literal notranslate"><span class="pre">Self</span></code> type as a <code class="docutils literal notranslate"><span class="pre">property</span></code> that returns that type:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">dataclasses</span> <span class="kn">import</span> <span class="n">dataclass</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">Generic</span><span class="p">,</span> <span class="n">TypeVar</span>
<span class="n">T</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">&quot;T&quot;</span><span class="p">)</span>
<span class="n">Self</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">&quot;Self&quot;</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="s2">&quot;LinkedList&quot;</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">LinkedList</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="nd">@property</span>
<span class="k">def</span> <span class="nf">next</span><span class="p">(</span><span class="bp">self</span><span class="p">:</span> <span class="n">Self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Self</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_next</span>
<span class="nd">@next</span><span class="o">.</span><span class="n">setter</span>
<span class="k">def</span> <span class="nf">next</span><span class="p">(</span><span class="bp">self</span><span class="p">:</span> <span class="n">Self</span><span class="p">,</span> <span class="nb">next</span><span class="p">:</span> <span class="n">Self</span> <span class="o">|</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_next</span> <span class="o">=</span> <span class="nb">next</span>
<span class="k">class</span> <span class="nc">OrdinalLinkedList</span><span class="p">(</span><span class="n">LinkedList</span><span class="p">[</span><span class="nb">int</span><span class="p">]):</span>
<span class="k">def</span> <span class="nf">ordinal_value</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">value</span><span class="p">)</span>
</pre></div>
</div>
</section>
<section id="use-in-generic-classes">
<h3><a class="toc-backref" href="#use-in-generic-classes" role="doc-backlink">Use in Generic Classes</a></h3>
<p><code class="docutils literal notranslate"><span class="pre">Self</span></code> can also be used in generic class methods:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Container</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="k">def</span> <span class="nf">set_value</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="n">T</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Self</span><span class="p">:</span> <span class="o">...</span>
</pre></div>
</div>
<p>This is equivalent to writing:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Self</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">&quot;Self&quot;</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="s2">&quot;Container[Any]&quot;</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">Container</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="k">def</span> <span class="nf">set_value</span><span class="p">(</span><span class="bp">self</span><span class="p">:</span> <span class="n">Self</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="n">T</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Self</span><span class="p">:</span> <span class="o">...</span>
</pre></div>
</div>
<p>The behavior is to preserve the type argument of the object on which the
method was called. When called on an object with concrete type
<code class="docutils literal notranslate"><span class="pre">Container[int]</span></code>, <code class="docutils literal notranslate"><span class="pre">Self</span></code> is bound to <code class="docutils literal notranslate"><span class="pre">Container[int]</span></code>. When called with
an object of generic type <code class="docutils literal notranslate"><span class="pre">Container[T]</span></code>, <code class="docutils literal notranslate"><span class="pre">Self</span></code> is bound to
<code class="docutils literal notranslate"><span class="pre">Container[T]</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">object_with_concrete_type</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">int_container</span><span class="p">:</span> <span class="n">Container</span><span class="p">[</span><span class="nb">int</span><span class="p">]</span>
<span class="n">str_container</span><span class="p">:</span> <span class="n">Container</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span>
<span class="n">reveal_type</span><span class="p">(</span><span class="n">int_container</span><span class="o">.</span><span class="n">set_value</span><span class="p">(</span><span class="mi">42</span><span class="p">))</span> <span class="c1"># =&gt; Container[int]</span>
<span class="n">reveal_type</span><span class="p">(</span><span class="n">str_container</span><span class="o">.</span><span class="n">set_value</span><span class="p">(</span><span class="s2">&quot;hello&quot;</span><span class="p">))</span> <span class="c1"># =&gt; Container[str]</span>
<span class="k">def</span> <span class="nf">object_with_generic_type</span><span class="p">(</span>
<span class="n">container</span><span class="p">:</span> <span class="n">Container</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="p">,</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Container</span><span class="p">[</span><span class="n">T</span><span class="p">]:</span>
<span class="k">return</span> <span class="n">container</span><span class="o">.</span><span class="n">set_value</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="c1"># =&gt; Container[T]</span>
</pre></div>
</div>
<p>The PEP doesnt specify the exact type of <code class="docutils literal notranslate"><span class="pre">self.value</span></code> within the method
<code class="docutils literal notranslate"><span class="pre">set_value</span></code>. Some type checkers may choose to implement <code class="docutils literal notranslate"><span class="pre">Self</span></code> types using
class-local type variables with <code class="docutils literal notranslate"><span class="pre">Self</span> <span class="pre">=</span> <span class="pre">TypeVar(“Self”,</span>
<span class="pre">bound=Container[T])</span></code>, which will infer a precise type <code class="docutils literal notranslate"><span class="pre">T</span></code>. However, given
that class-local type variables are not a standardized type system feature, it
is also acceptable to infer <code class="docutils literal notranslate"><span class="pre">Any</span></code> for <code class="docutils literal notranslate"><span class="pre">self.value</span></code>. We leave this up to
the type checker.</p>
<p>Note that we reject using <code class="docutils literal notranslate"><span class="pre">Self</span></code> with type arguments, such as <code class="docutils literal notranslate"><span class="pre">Self[int]</span></code>.
This is because it creates ambiguity about the type of the <code class="docutils literal notranslate"><span class="pre">self</span></code> parameter
and introduces unnecessary complexity:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Container</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="k">def</span> <span class="nf">foo</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">:</span> <span class="n">Self</span><span class="p">[</span><span class="nb">int</span><span class="p">],</span> <span class="n">other2</span><span class="p">:</span> <span class="n">Self</span><span class="p">,</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Self</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span> <span class="c1"># Rejected</span>
<span class="o">...</span>
</pre></div>
</div>
<p>In such cases, we recommend using an explicit type for <code class="docutils literal notranslate"><span class="pre">self</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Container</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="k">def</span> <span class="nf">foo</span><span class="p">(</span>
<span class="bp">self</span><span class="p">:</span> <span class="n">Container</span><span class="p">[</span><span class="n">T</span><span class="p">],</span>
<span class="n">other</span><span class="p">:</span> <span class="n">Container</span><span class="p">[</span><span class="nb">int</span><span class="p">],</span>
<span class="n">other2</span><span class="p">:</span> <span class="n">Container</span><span class="p">[</span><span class="n">T</span><span class="p">]</span>
<span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Container</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span> <span class="o">...</span>
</pre></div>
</div>
</section>
<section id="use-in-protocols">
<h3><a class="toc-backref" href="#use-in-protocols" role="doc-backlink">Use in Protocols</a></h3>
<p><code class="docutils literal notranslate"><span class="pre">Self</span></code> is valid within Protocols, similar to its use in classes:</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">Protocol</span><span class="p">,</span> <span class="n">Self</span>
<span class="k">class</span> <span class="nc">ShapeProtocol</span><span class="p">(</span><span class="n">Protocol</span><span class="p">):</span>
<span class="n">scale</span><span class="p">:</span> <span class="nb">float</span>
<span class="k">def</span> <span class="nf">set_scale</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">scale</span><span class="p">:</span> <span class="nb">float</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Self</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">scale</span> <span class="o">=</span> <span class="n">scale</span>
<span class="k">return</span> <span class="bp">self</span>
</pre></div>
</div>
<p>is treated equivalently to:</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">TypeVar</span>
<span class="n">SelfShape</span> <span class="o">=</span> <span class="n">TypeVar</span><span class="p">(</span><span class="s2">&quot;SelfShape&quot;</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="s2">&quot;ShapeProtocol&quot;</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">ShapeProtocol</span><span class="p">(</span><span class="n">Protocol</span><span class="p">):</span>
<span class="n">scale</span><span class="p">:</span> <span class="nb">float</span>
<span class="k">def</span> <span class="nf">set_scale</span><span class="p">(</span><span class="bp">self</span><span class="p">:</span> <span class="n">SelfShape</span><span class="p">,</span> <span class="n">scale</span><span class="p">:</span> <span class="nb">float</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">SelfShape</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">scale</span> <span class="o">=</span> <span class="n">scale</span>
<span class="k">return</span> <span class="bp">self</span>
</pre></div>
</div>
<p>See <a class="pep reference internal" href="../pep-0544/#self-types-in-protocols" title="PEP 544 Protocols: Structural subtyping (static duck typing) § Self-types in protocols">PEP 544</a> for
details on the behavior of TypeVars bound to protocols.</p>
<p>Checking a class for compatibility with a protocol: If a protocol uses
<code class="docutils literal notranslate"><span class="pre">Self</span></code> in methods or attribute annotations, then a class <code class="docutils literal notranslate"><span class="pre">Foo</span></code> is
considered compatible with the protocol if its corresponding methods and
attribute annotations use either <code class="docutils literal notranslate"><span class="pre">Self</span></code> or <code class="docutils literal notranslate"><span class="pre">Foo</span></code> or any of <code class="docutils literal notranslate"><span class="pre">Foo</span></code>s
subclasses. See the examples below:</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">Protocol</span>
<span class="k">class</span> <span class="nc">ShapeProtocol</span><span class="p">(</span><span class="n">Protocol</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">set_scale</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">scale</span><span class="p">:</span> <span class="nb">float</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Self</span><span class="p">:</span> <span class="o">...</span>
<span class="k">class</span> <span class="nc">ReturnSelf</span><span class="p">:</span>
<span class="n">scale</span><span class="p">:</span> <span class="nb">float</span> <span class="o">=</span> <span class="mf">1.0</span>
<span class="k">def</span> <span class="nf">set_scale</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">scale</span><span class="p">:</span> <span class="nb">float</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Self</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">scale</span> <span class="o">=</span> <span class="n">scale</span>
<span class="k">return</span> <span class="bp">self</span>
<span class="k">class</span> <span class="nc">ReturnConcreteShape</span><span class="p">:</span>
<span class="n">scale</span><span class="p">:</span> <span class="nb">float</span> <span class="o">=</span> <span class="mf">1.0</span>
<span class="k">def</span> <span class="nf">set_scale</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">scale</span><span class="p">:</span> <span class="nb">float</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">ReturnConcreteShape</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">scale</span> <span class="o">=</span> <span class="n">scale</span>
<span class="k">return</span> <span class="bp">self</span>
<span class="k">class</span> <span class="nc">BadReturnType</span><span class="p">:</span>
<span class="n">scale</span><span class="p">:</span> <span class="nb">float</span> <span class="o">=</span> <span class="mf">1.0</span>
<span class="k">def</span> <span class="nf">set_scale</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">scale</span><span class="p">:</span> <span class="nb">float</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">scale</span> <span class="o">=</span> <span class="n">scale</span>
<span class="k">return</span> <span class="mi">42</span>
<span class="k">class</span> <span class="nc">ReturnDifferentClass</span><span class="p">:</span>
<span class="n">scale</span><span class="p">:</span> <span class="nb">float</span> <span class="o">=</span> <span class="mf">1.0</span>
<span class="k">def</span> <span class="nf">set_scale</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">scale</span><span class="p">:</span> <span class="nb">float</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">ReturnConcreteShape</span><span class="p">:</span>
<span class="k">return</span> <span class="n">ReturnConcreteShape</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">accepts_shape</span><span class="p">(</span><span class="n">shape</span><span class="p">:</span> <span class="n">ShapeProtocol</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">y</span> <span class="o">=</span> <span class="n">shape</span><span class="o">.</span><span class="n">set_scale</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span>
<span class="n">reveal_type</span><span class="p">(</span><span class="n">y</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">return_self_shape</span><span class="p">:</span> <span class="n">ReturnSelf</span>
<span class="n">return_concrete_shape</span><span class="p">:</span> <span class="n">ReturnConcreteShape</span>
<span class="n">bad_return_type</span><span class="p">:</span> <span class="n">BadReturnType</span>
<span class="n">return_different_class</span><span class="p">:</span> <span class="n">ReturnDifferentClass</span>
<span class="n">accepts_shape</span><span class="p">(</span><span class="n">return_self_shape</span><span class="p">)</span> <span class="c1"># OK</span>
<span class="n">accepts_shape</span><span class="p">(</span><span class="n">return_concrete_shape</span><span class="p">)</span> <span class="c1"># OK</span>
<span class="n">accepts_shape</span><span class="p">(</span><span class="n">bad_return_type</span><span class="p">)</span> <span class="c1"># Not OK</span>
<span class="c1"># Not OK because it returns a non-subclass.</span>
<span class="n">accepts_shape</span><span class="p">(</span><span class="n">return_different_class</span><span class="p">)</span>
</pre></div>
</div>
</section>
</section>
<section id="valid-locations-for-self">
<h2><a class="toc-backref" href="#valid-locations-for-self" role="doc-backlink">Valid Locations for <code class="docutils literal notranslate"><span class="pre">Self</span></code></a></h2>
<p>A <code class="docutils literal notranslate"><span class="pre">Self</span></code> annotation is only valid in class contexts, and will always refer
to the encapsulating class. In contexts involving nested classes, <code class="docutils literal notranslate"><span class="pre">Self</span></code>
will always refer to the innermost class.</p>
<p>The following uses of <code class="docutils literal notranslate"><span class="pre">Self</span></code> are accepted:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">ReturnsSelf</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">-&gt;</span> <span class="n">Self</span><span class="p">:</span> <span class="o">...</span> <span class="c1"># Accepted</span>
<span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">bar</span><span class="p">(</span><span class="bp">cls</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Self</span><span class="p">:</span> <span class="c1"># Accepted</span>
<span class="k">return</span> <span class="bp">cls</span><span class="p">()</span>
<span class="k">def</span> <span class="fm">__new__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Self</span><span class="p">:</span> <span class="o">...</span> <span class="c1"># Accepted</span>
<span class="k">def</span> <span class="nf">explicitly_use_self</span><span class="p">(</span><span class="bp">self</span><span class="p">:</span> <span class="n">Self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Self</span><span class="p">:</span> <span class="o">...</span> <span class="c1"># Accepted</span>
<span class="c1"># Accepted (Self can be nested within other types)</span>
<span class="k">def</span> <span class="nf">returns_list</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="n">Self</span><span class="p">]:</span> <span class="o">...</span>
<span class="c1"># Accepted (Self can be nested within other types)</span>
<span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">return_cls</span><span class="p">(</span><span class="bp">cls</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">type</span><span class="p">[</span><span class="n">Self</span><span class="p">]:</span>
<span class="k">return</span> <span class="bp">cls</span>
<span class="k">class</span> <span class="nc">Child</span><span class="p">(</span><span class="n">ReturnsSelf</span><span class="p">):</span>
<span class="c1"># Accepted (we can override a method that uses Self annotations)</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">-&gt;</span> <span class="n">Self</span><span class="p">:</span> <span class="o">...</span>
<span class="k">class</span> <span class="nc">TakesSelf</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="n">other</span><span class="p">:</span> <span class="n">Self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span> <span class="o">...</span> <span class="c1"># Accepted</span>
<span class="k">class</span> <span class="nc">Recursive</span><span class="p">:</span>
<span class="c1"># Accepted (treated as an @property returning ``Self | None``)</span>
<span class="nb">next</span><span class="p">:</span> <span class="n">Self</span> <span class="o">|</span> <span class="kc">None</span>
<span class="k">class</span> <span class="nc">CallableAttribute</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">-&gt;</span> <span class="nb">int</span><span class="p">:</span> <span class="o">...</span>
<span class="c1"># Accepted (treated as an @property returning the Callable type)</span>
<span class="n">bar</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[[</span><span class="n">Self</span><span class="p">],</span> <span class="nb">int</span><span class="p">]</span> <span class="o">=</span> <span class="n">foo</span>
<span class="k">class</span> <span class="nc">HasNestedFunction</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="mi">42</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">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="c1"># Accepted (Self is bound to HasNestedFunction).</span>
<span class="k">def</span> <span class="nf">nested</span><span class="p">(</span><span class="n">z</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">inner_self</span><span class="p">:</span> <span class="n">Self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Self</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="n">z</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">inner_self</span><span class="o">.</span><span class="n">x</span><span class="p">)</span>
<span class="k">return</span> <span class="n">inner_self</span>
<span class="n">nested</span><span class="p">(</span><span class="mi">42</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span> <span class="c1"># OK</span>
<span class="k">class</span> <span class="nc">Outer</span><span class="p">:</span>
<span class="k">class</span> <span class="nc">Inner</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">-&gt;</span> <span class="n">Self</span><span class="p">:</span> <span class="o">...</span> <span class="c1"># Accepted (Self is bound to Inner)</span>
</pre></div>
</div>
<p>The following uses of <code class="docutils literal notranslate"><span class="pre">Self</span></code> are rejected.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="n">bar</span><span class="p">:</span> <span class="n">Self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Self</span><span class="p">:</span> <span class="o">...</span> <span class="c1"># Rejected (not within a class)</span>
<span class="n">bar</span><span class="p">:</span> <span class="n">Self</span> <span class="c1"># Rejected (not within a class)</span>
<span class="k">class</span> <span class="nc">Foo</span><span class="p">:</span>
<span class="c1"># Rejected (Self is treated as unknown).</span>
<span class="k">def</span> <span class="nf">has_existing_self_annotation</span><span class="p">(</span><span class="bp">self</span><span class="p">:</span> <span class="n">T</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Self</span><span class="p">:</span> <span class="o">...</span>
<span class="k">class</span> <span class="nc">Foo</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">return_concrete_type</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Self</span><span class="p">:</span>
<span class="k">return</span> <span class="n">Foo</span><span class="p">()</span> <span class="c1"># Rejected (see FooChild below for rationale)</span>
<span class="k">class</span> <span class="nc">FooChild</span><span class="p">(</span><span class="n">Foo</span><span class="p">):</span>
<span class="n">child_value</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">42</span>
<span class="k">def</span> <span class="nf">child_method</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
<span class="c1"># At runtime, this would be Foo, not FooChild.</span>
<span class="n">y</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">return_concrete_type</span><span class="p">()</span>
<span class="n">y</span><span class="o">.</span><span class="n">child_value</span>
<span class="c1"># Runtime error: Foo has no attribute child_value</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="k">def</span> <span class="nf">bar</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">T</span><span class="p">:</span> <span class="o">...</span>
<span class="k">class</span> <span class="nc">Baz</span><span class="p">(</span><span class="n">Bar</span><span class="p">[</span><span class="n">Self</span><span class="p">]):</span> <span class="o">...</span> <span class="c1"># Rejected</span>
</pre></div>
</div>
<p>We reject type aliases containing <code class="docutils literal notranslate"><span class="pre">Self</span></code>. Supporting <code class="docutils literal notranslate"><span class="pre">Self</span></code>
outside class definitions can require a lot of special-handling in
type checkers. Given that it also goes against the rest of the PEP to
use <code class="docutils literal notranslate"><span class="pre">Self</span></code> outside a class definition, we believe the added
convenience of aliases is not worth it:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">TupleSelf</span> <span class="o">=</span> <span class="n">Tuple</span><span class="p">[</span><span class="n">Self</span><span class="p">,</span> <span class="n">Self</span><span class="p">]</span> <span class="c1"># Rejected</span>
<span class="k">class</span> <span class="nc">Alias</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">return_tuple</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">TupleSelf</span><span class="p">:</span> <span class="c1"># Rejected</span>
<span class="k">return</span> <span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span>
</pre></div>
</div>
<p>Note that we reject <code class="docutils literal notranslate"><span class="pre">Self</span></code> in staticmethods. <code class="docutils literal notranslate"><span class="pre">Self</span></code> does not add much
value since there is no <code class="docutils literal notranslate"><span class="pre">self</span></code> or <code class="docutils literal notranslate"><span class="pre">cls</span></code> to return. The only possible use
cases would be to return a parameter itself or some element from a container
passed in as a parameter. These dont seem worth the additional complexity.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Base</span><span class="p">:</span>
<span class="nd">@staticmethod</span>
<span class="k">def</span> <span class="nf">make</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="n">Self</span><span class="p">:</span> <span class="c1"># Rejected</span>
<span class="o">...</span>
<span class="nd">@staticmethod</span>
<span class="k">def</span> <span class="nf">return_parameter</span><span class="p">(</span><span class="n">foo</span><span class="p">:</span> <span class="n">Self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Self</span><span class="p">:</span> <span class="c1"># Rejected</span>
<span class="o">...</span>
</pre></div>
</div>
<p>Likewise, we reject <code class="docutils literal notranslate"><span class="pre">Self</span></code> in metaclasses. <code class="docutils literal notranslate"><span class="pre">Self</span></code> in this PEP consistently
refers to the same type (that of <code class="docutils literal notranslate"><span class="pre">self</span></code>). But in metaclasses, it would have
to refer to different types in different method signatures. For example, in
<code class="docutils literal notranslate"><span class="pre">__mul__</span></code>, <code class="docutils literal notranslate"><span class="pre">Self</span></code> in the return type would refer to the implementing class
<code class="docutils literal notranslate"><span class="pre">Foo</span></code>, not the enclosing class <code class="docutils literal notranslate"><span class="pre">MyMetaclass</span></code>. But, in <code class="docutils literal notranslate"><span class="pre">__new__</span></code>, <code class="docutils literal notranslate"><span class="pre">Self</span></code>
in the return type would refer to the enclosing class <code class="docutils literal notranslate"><span class="pre">MyMetaclass</span></code>. To
avoid confusion, we reject this edge case.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">MyMetaclass</span><span class="p">(</span><span class="nb">type</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__new__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">:</span> <span class="n">Any</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Self</span><span class="p">:</span> <span class="c1"># Rejected</span>
<span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__new__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">)</span>
<span class="k">def</span> <span class="fm">__mul__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">count</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="n">Self</span><span class="p">]:</span> <span class="c1"># Rejected</span>
<span class="k">return</span> <span class="p">[</span><span class="bp">cls</span><span class="p">()]</span> <span class="o">*</span> <span class="n">count</span>
<span class="k">class</span> <span class="nc">Foo</span><span class="p">(</span><span class="n">metaclass</span><span class="o">=</span><span class="n">MyMetaclass</span><span class="p">):</span> <span class="o">...</span>
</pre></div>
</div>
</section>
<section id="runtime-behavior">
<h2><a class="toc-backref" href="#runtime-behavior" role="doc-backlink">Runtime behavior</a></h2>
<p>Because <code class="docutils literal notranslate"><span class="pre">Self</span></code> is not subscriptable, we propose an implementation similar to
<code class="docutils literal notranslate"><span class="pre">typing.NoReturn</span></code>.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@_SpecialForm</span>
<span class="k">def</span> <span class="nf">Self</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Used to spell the type of &quot;self&quot; in classes.</span>
<span class="sd"> Example::</span>
<span class="sd"> from typing import Self</span>
<span class="sd"> class ReturnsSelf:</span>
<span class="sd"> def parse(self, data: bytes) -&gt; Self:</span>
<span class="sd"> ...</span>
<span class="sd"> return self</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="bp">self</span><span class="si">}</span><span class="s2"> is not subscriptable&quot;</span><span class="p">)</span>
</pre></div>
</div>
</section>
<section id="rejected-alternatives">
<h2><a class="toc-backref" href="#rejected-alternatives" role="doc-backlink">Rejected Alternatives</a></h2>
<section id="allow-the-type-checker-to-infer-the-return-type">
<h3><a class="toc-backref" href="#allow-the-type-checker-to-infer-the-return-type" role="doc-backlink">Allow the Type Checker to Infer the Return Type</a></h3>
<p>One proposal is to leave the <code class="docutils literal notranslate"><span class="pre">Self</span></code> type implicit and let the type checker
infer from the body of the method that the return type must be the same as the
type of the <code class="docutils literal notranslate"><span class="pre">self</span></code> parameter:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Shape</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">set_scale</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">scale</span><span class="p">:</span> <span class="nb">float</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">scale</span> <span class="o">=</span> <span class="n">scale</span>
<span class="k">return</span> <span class="bp">self</span> <span class="c1"># Type checker infers that we are returning self</span>
</pre></div>
</div>
<p>We reject this because Explicit Is Better Than Implicit. Beyond that, the
above approach will fail for type stubs, which dont have method bodies to
analyze.</p>
</section>
</section>
<section id="reference-implementations">
<h2><a class="toc-backref" href="#reference-implementations" role="doc-backlink">Reference Implementations</a></h2>
<p>Mypy: Proof of concept implementation in <a class="reference external" href="https://github.com/Gobot1234/mypy">Mypy</a>.</p>
<p>Pyright: v1.1.184</p>
<p>Runtime implementation of <code class="docutils literal notranslate"><span class="pre">Self</span></code>: <a class="reference external" href="https://github.com/python/typing/pull/933">PR</a>.</p>
</section>
<section id="resources">
<h2><a class="toc-backref" href="#resources" role="doc-backlink">Resources</a></h2>
<p>Similar discussions on a <code class="docutils literal notranslate"><span class="pre">Self</span></code> type in Python started in Mypy around 2016:
<a class="reference external" href="https://github.com/python/mypy/issues/1212">Mypy issue #1212</a> - SelfType or
another way to spell “type of self”. However, the approach ultimately taken
there was the bounded <code class="docutils literal notranslate"><span class="pre">TypeVar</span></code> approach shown in our “before” examples.
Other issues that discuss this include <a class="reference external" href="https://github.com/python/mypy/issues/2354">Mypy issue #2354</a> - Self types in generic
classes.</p>
<dl class="simple">
<dt>Pradeep made a concrete proposal at the PyCon Typing Summit 2021:</dt><dd><a class="reference external" href="https://youtu.be/ld9rwCvGdhc?t=3260">recorded talk</a>, <a class="reference external" href="https://drive.google.com/file/d/1x-qoDVY_OvLpIV1EwT7m3vm4HrgubHPG/view">slides</a>.</dd>
</dl>
<p>James brought up the proposal independently on typing-sig:
<a class="reference external" href="https://mail.python.org/archives/list/typing-sig&#64;python.org/thread/SJAANGA2CWZ6D6TJ7KOPG7PZQC56K73S/#B2CBLQDHXQ5HMFUMS4VNY2D4YDCFT64Q">Typing-sig thread</a>.</p>
<p>Other languages have similar ways to express the type of the enclosing class:</p>
<ul class="simple">
<li>TypeScript has the <code class="docutils literal notranslate"><span class="pre">this</span></code> type (<a class="reference external" href="https://typescriptlang.org/docs/handbook/2/classes.html#this-types">TypeScript docs</a>)</li>
<li>Rust has the <code class="docutils literal notranslate"><span class="pre">Self</span></code> type (<a class="reference external" href="https://doc.rust-lang.org/std/keyword.SelfTy.html">Rust docs</a>)</li>
</ul>
<p>Thanks to the following people for their feedback on the PEP:</p>
<p>Jia Chen, Rebecca Chen, Sergei Lebedev, Kaylynn Morgan, Tuomas
Suutari, Eric Traut, Alex Waygood, Shannon Zhu, and Никита Соболев</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-0673.rst">https://github.com/python/peps/blob/main/peps/pep-0673.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0673.rst">2024-02-07 16:26: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><ul>
<li><a class="reference internal" href="#usage-statistics">Usage statistics</a></li>
</ul>
</li>
<li><a class="reference internal" href="#specification">Specification</a><ul>
<li><a class="reference internal" href="#use-in-method-signatures">Use in Method Signatures</a></li>
<li><a class="reference internal" href="#use-in-classmethod-signatures">Use in Classmethod Signatures</a></li>
<li><a class="reference internal" href="#use-in-parameter-types">Use in Parameter Types</a></li>
<li><a class="reference internal" href="#use-in-attribute-annotations">Use in Attribute Annotations</a></li>
<li><a class="reference internal" href="#use-in-generic-classes">Use in Generic Classes</a></li>
<li><a class="reference internal" href="#use-in-protocols">Use in Protocols</a></li>
</ul>
</li>
<li><a class="reference internal" href="#valid-locations-for-self">Valid Locations for <code class="docutils literal notranslate"><span class="pre">Self</span></code></a></li>
<li><a class="reference internal" href="#runtime-behavior">Runtime behavior</a></li>
<li><a class="reference internal" href="#rejected-alternatives">Rejected Alternatives</a><ul>
<li><a class="reference internal" href="#allow-the-type-checker-to-infer-the-return-type">Allow the Type Checker to Infer the Return Type</a></li>
</ul>
</li>
<li><a class="reference internal" href="#reference-implementations">Reference Implementations</a></li>
<li><a class="reference internal" href="#resources">Resources</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-0673.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>