python-peps/pep-3155/index.html

292 lines
19 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

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

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="color-scheme" content="light dark">
<title>PEP 3155 Qualified name for classes and functions | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-3155/">
<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 3155 Qualified name for classes and functions | peps.python.org'>
<meta property="og:description" content="Python Enhancement Proposals (PEPs)">
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-3155/">
<meta property="og:site_name" content="Python Enhancement Proposals (PEPs)">
<meta property="og:image" content="https://peps.python.org/_static/og-image.png">
<meta property="og:image:alt" content="Python PEPs">
<meta property="og:image:width" content="200">
<meta property="og:image:height" content="200">
<meta name="description" content="Python Enhancement Proposals (PEPs)">
<meta name="theme-color" content="#3776ab">
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all">
<title>Following system colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="9"></circle>
<path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path>
</svg>
</symbol>
<symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all">
<title>Selected dark colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path>
</svg>
</symbol>
<symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all">
<title>Selected light colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
</symbol>
</svg>
<script>
document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto"
</script>
<section id="pep-page-section">
<header>
<h1>Python Enhancement Proposals</h1>
<ul class="breadcrumbs">
<li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> &raquo; </li>
<li><a href="../pep-0000/">PEP Index</a> &raquo; </li>
<li>PEP 3155</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 3155 Qualified name for classes and functions</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Antoine Pitrou &lt;solipsis&#32;&#97;t&#32;pitrou.net&gt;</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">Created<span class="colon">:</span></dt>
<dd class="field-even">29-Oct-2011</dd>
<dt class="field-odd">Python-Version<span class="colon">:</span></dt>
<dd class="field-odd">3.3</dd>
<dt class="field-even">Post-History<span class="colon">:</span></dt>
<dd class="field-even"><p></p></dd>
<dt class="field-odd">Resolution<span class="colon">:</span></dt>
<dd class="field-odd"><a class="reference external" href="https://mail.python.org/pipermail/python-dev/2011-November/114545.html">Python-Dev message</a></dd>
</dl>
<hr class="docutils" />
<section id="contents">
<details><summary>Table of Contents</summary><ul class="simple">
<li><a class="reference internal" href="#rationale">Rationale</a></li>
<li><a class="reference internal" href="#proposal">Proposal</a><ul>
<li><a class="reference internal" href="#example-with-nested-classes">Example with nested classes</a></li>
<li><a class="reference internal" href="#example-with-nested-functions">Example with nested functions</a></li>
</ul>
</li>
<li><a class="reference internal" href="#limitations">Limitations</a></li>
<li><a class="reference internal" href="#discussion">Discussion</a><ul>
<li><a class="reference internal" href="#excluding-the-module-name">Excluding the module name</a></li>
<li><a class="reference internal" href="#reviving-unbound-methods">Reviving unbound methods</a></li>
</ul>
</li>
<li><a class="reference internal" href="#naming-choice">Naming choice</a></li>
<li><a class="reference internal" href="#references">References</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
</details></section>
<section id="rationale">
<h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2>
<p>Pythons introspection facilities have long had poor support for
nested classes. Given a class object, it is impossible to know
whether it was defined inside another class or at module top-level;
and, if the former, it is also impossible to know in which class it
was defined. While use of nested classes is often considered poor
style, the only reason for them to have second class introspection
support is a lousy pun.</p>
<p>Python 3 adds insult to injury by dropping what was formerly known as
unbound methods. In Python 2, given the following definition:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">C</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">f</span><span class="p">():</span>
<span class="k">pass</span>
</pre></div>
</div>
<p>you can then walk up from the <code class="docutils literal notranslate"><span class="pre">C.f</span></code> object to its defining class:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">C</span><span class="o">.</span><span class="n">f</span><span class="o">.</span><span class="n">im_class</span>
<span class="go">&lt;class &#39;__main__.C&#39;&gt;</span>
</pre></div>
</div>
<p>This possibility is gone in Python 3:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">C</span><span class="o">.</span><span class="n">f</span><span class="o">.</span><span class="n">im_class</span>
<span class="gt">Traceback (most recent call last):</span>
File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n">&lt;module&gt;</span>
<span class="gr">AttributeError</span>: <span class="n">&#39;function&#39; object has no attribute &#39;im_class&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">dir</span><span class="p">(</span><span class="n">C</span><span class="o">.</span><span class="n">f</span><span class="p">)</span>
<span class="go">[&#39;__annotations__&#39;, &#39;__call__&#39;, &#39;__class__&#39;, &#39;__closure__&#39;, &#39;__code__&#39;,</span>
<span class="go">&#39;__defaults__&#39;, &#39;__delattr__&#39;, &#39;__dict__&#39;, &#39;__dir__&#39;, &#39;__doc__&#39;,</span>
<span class="go">&#39;__eq__&#39;, &#39;__format__&#39;, &#39;__ge__&#39;, &#39;__get__&#39;, &#39;__getattribute__&#39;,</span>
<span class="go">&#39;__globals__&#39;, &#39;__gt__&#39;, &#39;__hash__&#39;, &#39;__init__&#39;, &#39;__kwdefaults__&#39;,</span>
<span class="go">&#39;__le__&#39;, &#39;__lt__&#39;, &#39;__module__&#39;, &#39;__name__&#39;, &#39;__ne__&#39;, &#39;__new__&#39;,</span>
<span class="go">&#39;__reduce__&#39;, &#39;__reduce_ex__&#39;, &#39;__repr__&#39;, &#39;__setattr__&#39;, &#39;__sizeof__&#39;,</span>
<span class="go">&#39;__str__&#39;, &#39;__subclasshook__&#39;]</span>
</pre></div>
</div>
<p>This limits again the introspection capabilities available to the
user. It can produce actual issues when porting software to Python 3,
for example Twisted Core where the issue of introspecting method
objects came up several times. It also limits pickling support <a class="footnote-reference brackets" href="#id3" id="id1">[1]</a>.</p>
</section>
<section id="proposal">
<h2><a class="toc-backref" href="#proposal" role="doc-backlink">Proposal</a></h2>
<p>This PEP proposes the addition of a <code class="docutils literal notranslate"><span class="pre">__qualname__</span></code> attribute to
functions and classes. For top-level functions and classes, the
<code class="docutils literal notranslate"><span class="pre">__qualname__</span></code> attribute is equal to the <code class="docutils literal notranslate"><span class="pre">__name__</span></code> attribute. For
nested classes, methods, and nested functions, the <code class="docutils literal notranslate"><span class="pre">__qualname__</span></code>
attribute contains a dotted path leading to the object from the module
top-level. A functions local namespace is represented in that dotted
path by a component named <code class="docutils literal notranslate"><span class="pre">&lt;locals&gt;</span></code>.</p>
<p>The repr() and str() of functions and classes is modified to use
<code class="docutils literal notranslate"><span class="pre">__qualname__</span></code> rather than <code class="docutils literal notranslate"><span class="pre">__name__</span></code>.</p>
<section id="example-with-nested-classes">
<h3><a class="toc-backref" href="#example-with-nested-classes" role="doc-backlink">Example with nested classes</a></h3>
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="k">class</span> <span class="nc">C</span><span class="p">:</span>
<span class="gp">... </span> <span class="k">def</span> <span class="nf">f</span><span class="p">():</span> <span class="k">pass</span>
<span class="gp">... </span> <span class="k">class</span> <span class="nc">D</span><span class="p">:</span>
<span class="gp">... </span> <span class="k">def</span> <span class="nf">g</span><span class="p">():</span> <span class="k">pass</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">C</span><span class="o">.</span><span class="vm">__qualname__</span>
<span class="go">&#39;C&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">C</span><span class="o">.</span><span class="n">f</span><span class="o">.</span><span class="vm">__qualname__</span>
<span class="go">&#39;C.f&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">C</span><span class="o">.</span><span class="n">D</span><span class="o">.</span><span class="vm">__qualname__</span>
<span class="go">&#39;C.D&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">C</span><span class="o">.</span><span class="n">D</span><span class="o">.</span><span class="n">g</span><span class="o">.</span><span class="vm">__qualname__</span>
<span class="go">&#39;C.D.g&#39;</span>
</pre></div>
</div>
</section>
<section id="example-with-nested-functions">
<h3><a class="toc-backref" href="#example-with-nested-functions" role="doc-backlink">Example with nested functions</a></h3>
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="k">def</span> <span class="nf">f</span><span class="p">():</span>
<span class="gp">... </span> <span class="k">def</span> <span class="nf">g</span><span class="p">():</span> <span class="k">pass</span>
<span class="gp">... </span> <span class="k">return</span> <span class="n">g</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">f</span><span class="o">.</span><span class="vm">__qualname__</span>
<span class="go">&#39;f&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">f</span><span class="p">()</span><span class="o">.</span><span class="vm">__qualname__</span>
<span class="go">&#39;f.&lt;locals&gt;.g&#39;</span>
</pre></div>
</div>
</section>
</section>
<section id="limitations">
<h2><a class="toc-backref" href="#limitations" role="doc-backlink">Limitations</a></h2>
<p>With nested functions (and classes defined inside functions), the
dotted path will not be walkable programmatically as a functions
namespace is not available from the outside. It will still be more
helpful to the human reader than the bare <code class="docutils literal notranslate"><span class="pre">__name__</span></code>.</p>
<p>As the <code class="docutils literal notranslate"><span class="pre">__name__</span></code> attribute, the <code class="docutils literal notranslate"><span class="pre">__qualname__</span></code> attribute is computed
statically and it will not automatically follow rebinding.</p>
</section>
<section id="discussion">
<h2><a class="toc-backref" href="#discussion" role="doc-backlink">Discussion</a></h2>
<section id="excluding-the-module-name">
<h3><a class="toc-backref" href="#excluding-the-module-name" role="doc-backlink">Excluding the module name</a></h3>
<p>As <code class="docutils literal notranslate"><span class="pre">__name__</span></code>, <code class="docutils literal notranslate"><span class="pre">__qualname__</span></code> doesnt include the module name. This
makes it independent of module aliasing and rebinding, and also allows to
compute it at compile time.</p>
</section>
<section id="reviving-unbound-methods">
<h3><a class="toc-backref" href="#reviving-unbound-methods" role="doc-backlink">Reviving unbound methods</a></h3>
<p>Reviving unbound methods would only solve a fraction of the problems this
PEP solves, at a higher price (an additional object type and an additional
indirection, rather than an additional attribute).</p>
</section>
</section>
<section id="naming-choice">
<h2><a class="toc-backref" href="#naming-choice" role="doc-backlink">Naming choice</a></h2>
<p>“Qualified name” is the best approximation, as a short phrase, of what the
additional attribute is about. It is not a “full name” or “fully qualified
name” since it (deliberately) does not include the module name. Calling
it a “path” would risk confusion with filesystem paths and the <code class="docutils literal notranslate"><span class="pre">__file__</span></code>
attribute.</p>
<p>The first proposal for the attribute name was to call it <code class="docutils literal notranslate"><span class="pre">__qname__</span></code> but
many people (who are not aware of previous use of such jargon in e.g. the
XML specification <a class="footnote-reference brackets" href="#id4" id="id2">[2]</a>) found it obscure and non-obvious, which is why the
slightly less short and more explicit <code class="docutils literal notranslate"><span class="pre">__qualname__</span></code> was finally chosen.</p>
</section>
<section id="references">
<h2><a class="toc-backref" href="#references" role="doc-backlink">References</a></h2>
<aside class="footnote-list brackets">
<aside class="footnote brackets" id="id3" role="doc-footnote">
<dt class="label" id="id3">[<a href="#id1">1</a>]</dt>
<dd>“pickle should support methods”:
<a class="reference external" href="http://bugs.python.org/issue9276">http://bugs.python.org/issue9276</a></aside>
<aside class="footnote brackets" id="id4" role="doc-footnote">
<dt class="label" id="id4">[<a href="#id2">2</a>]</dt>
<dd>“QName” entry in Wikipedia:
<a class="reference external" href="http://en.wikipedia.org/wiki/QName">http://en.wikipedia.org/wiki/QName</a></aside>
</aside>
</section>
<section id="copyright">
<h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2>
<p>This document has been placed in the public domain.</p>
</section>
</section>
<hr class="docutils" />
<p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-3155.rst">https://github.com/python/peps/blob/main/peps/pep-3155.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-3155.rst">2023-09-09 17:39:29 GMT</a></p>
</article>
<nav id="pep-sidebar">
<h2>Contents</h2>
<ul>
<li><a class="reference internal" href="#rationale">Rationale</a></li>
<li><a class="reference internal" href="#proposal">Proposal</a><ul>
<li><a class="reference internal" href="#example-with-nested-classes">Example with nested classes</a></li>
<li><a class="reference internal" href="#example-with-nested-functions">Example with nested functions</a></li>
</ul>
</li>
<li><a class="reference internal" href="#limitations">Limitations</a></li>
<li><a class="reference internal" href="#discussion">Discussion</a><ul>
<li><a class="reference internal" href="#excluding-the-module-name">Excluding the module name</a></li>
<li><a class="reference internal" href="#reviving-unbound-methods">Reviving unbound methods</a></li>
</ul>
</li>
<li><a class="reference internal" href="#naming-choice">Naming choice</a></li>
<li><a class="reference internal" href="#references">References</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
<br>
<a id="source" href="https://github.com/python/peps/blob/main/peps/pep-3155.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>