mirror of https://github.com/python/peps
853 lines
89 KiB
HTML
853 lines
89 KiB
HTML
|
||
<!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> » </li>
|
||
<li><a href="../pep-0000/">PEP Index</a> » </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 <gohanpra at gmail.com>,
|
||
James Hilton-Balfe <gobot1234yt at gmail.com></dd>
|
||
<dt class="field-even">Sponsor<span class="colon">:</span></dt>
|
||
<dd class="field-even">Jelle Zijlstra <jelle.zijlstra at gmail.com></dd>
|
||
<dt class="field-odd">Discussions-To<span class="colon">:</span></dt>
|
||
<dd class="field-odd"><a class="reference external" href="https://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">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@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"># => 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">-></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"># => 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">-></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"># => 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">"TShape"</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="s2">"Shape"</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">-></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">-></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"># => 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 doesn’t 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="Shape")</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">-></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">-></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">-></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">"SelfShape"</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="s2">"Shape"</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">-></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">-></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">"SelfCircle"</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="s2">"Circle"</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">-></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">-></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">-></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">"scale"</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">-></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">"scale"</span><span class="p">:</span> <span class="mf">7.0</span><span class="p">})</span>
|
||
<span class="c1"># => 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">"scale"</span><span class="p">:</span> <span class="mf">7.0</span><span class="p">})</span>
|
||
<span class="c1"># => *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">"Self"</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="s2">"Shape"</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">-></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">"scale"</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">-></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">"scale"</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">"Self"</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="s2">"Shape"</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">-></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">-></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">-></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">-></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">-></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">"T"</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">"hello"</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">-></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">-></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">"T"</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">"Self"</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="s2">"LinkedList"</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">-></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">-></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">-></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">-></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">"Self"</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="s2">"Container[Any]"</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">-></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">-></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"># => 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">"hello"</span><span class="p">))</span> <span class="c1"># => 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">-></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"># => Container[T]</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The PEP doesn’t 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">-></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">-></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">-></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">"SelfShape"</span><span class="p">,</span> <span class="n">bound</span><span class="o">=</span><span class="s2">"ShapeProtocol"</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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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">-></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 don’t 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">-></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">-></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">-></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">-></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">"""Used to spell the type of "self" 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) -> Self:</span>
|
||
<span class="sd"> ...</span>
|
||
<span class="sd"> return self</span>
|
||
|
||
<span class="sd"> """</span>
|
||
<span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="bp">self</span><span class="si">}</span><span class="s2"> is not subscriptable"</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 don’t 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@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> |