python-peps/pep-0232/index.html

364 lines
24 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 232 Function Attributes | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-0232/">
<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 232 Function Attributes | peps.python.org'>
<meta property="og:description" content="This PEP describes an extension to Python, adding attribute dictionaries to functions and methods. This PEP tracks the status and ownership of this feature. It contains a description of the feature and outlines changes necessary to support the feature...">
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-0232/">
<meta property="og:site_name" content="Python Enhancement Proposals (PEPs)">
<meta property="og:image" content="https://peps.python.org/_static/og-image.png">
<meta property="og:image:alt" content="Python PEPs">
<meta property="og:image:width" content="200">
<meta property="og:image:height" content="200">
<meta name="description" content="This PEP describes an extension to Python, adding attribute dictionaries to functions and methods. This PEP tracks the status and ownership of this feature. It contains a description of the feature and outlines changes necessary to support the feature...">
<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 232</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 232 Function Attributes</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Barry Warsaw &lt;barry&#32;&#97;t&#32;python.org&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">02-Dec-2000</dd>
<dt class="field-odd">Python-Version<span class="colon">:</span></dt>
<dd class="field-odd">2.1</dd>
<dt class="field-even">Post-History<span class="colon">:</span></dt>
<dd class="field-even">20-Feb-2001</dd>
</dl>
<hr class="docutils" />
<section id="contents">
<details><summary>Table of Contents</summary><ul class="simple">
<li><a class="reference internal" href="#introduction">Introduction</a></li>
<li><a class="reference internal" href="#background">Background</a></li>
<li><a class="reference internal" href="#proposal">Proposal</a></li>
<li><a class="reference internal" href="#examples">Examples</a><ul>
<li><a class="reference internal" href="#other-uses">Other Uses</a></li>
</ul>
</li>
<li><a class="reference internal" href="#future-directions">Future Directions</a></li>
<li><a class="reference internal" href="#dissenting-opinion">Dissenting Opinion</a></li>
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</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="introduction">
<h2><a class="toc-backref" href="#introduction" role="doc-backlink">Introduction</a></h2>
<p>This PEP describes an extension to Python, adding attribute
dictionaries to functions and methods. This PEP tracks the status
and ownership of this feature. It contains a description of the
feature and outlines changes necessary to support the feature.
This PEP summarizes discussions held in mailing list forums, and
provides URLs for further information, where appropriate. The CVS
revision history of this file contains the definitive historical
record.</p>
</section>
<section id="background">
<h2><a class="toc-backref" href="#background" role="doc-backlink">Background</a></h2>
<p>Functions already have a number of attributes, some of which are
writable, e.g. <code class="docutils literal notranslate"><span class="pre">func_doc</span></code>, a.k.a. <code class="docutils literal notranslate"><span class="pre">func.__doc__</span></code>. <code class="docutils literal notranslate"><span class="pre">func_doc</span></code>
has the interesting property that there is special syntax in
function (and method) definitions for implicitly setting the
attribute. This convenience has been exploited over and over again,
overloading docstrings with additional semantics.</p>
<p>For example, John Aycock has written a system where docstrings are
used to define parsing rules. <a class="footnote-reference brackets" href="#id4" id="id1">[1]</a> Zopes ZPublisher ORB <a class="footnote-reference brackets" href="#id5" id="id2">[2]</a> uses
docstrings to signal publishable methods, i.e. methods that can
be called through the web.</p>
<p>The problem with this approach is that the overloaded semantics
may conflict with each other. For example, if we wanted to add a
doctest unit test to a Zope method that should not be publishable
through the web.</p>
</section>
<section id="proposal">
<h2><a class="toc-backref" href="#proposal" role="doc-backlink">Proposal</a></h2>
<p>This proposal adds a new dictionary to function objects, called
<code class="docutils literal notranslate"><span class="pre">func_dict</span></code> (a.k.a. <code class="docutils literal notranslate"><span class="pre">__dict__</span></code>). This dictionary can be set
and get using ordinary attribute set and get syntax.</p>
<p>Methods also gain getter syntax, and they currently access the
attribute through the dictionary of the underlying function
object. It is not possible to set attributes on bound or unbound
methods, except by doing so explicitly on the underlying function
object. See the <a class="reference internal" href="#future-directions">Future Directions</a> discussion below for
approaches in subsequent versions of Python.</p>
<p>A function objects <code class="docutils literal notranslate"><span class="pre">__dict__</span></code> can also be set, but only to a
dictionary object. Deleting a functions <code class="docutils literal notranslate"><span class="pre">__dict__</span></code>, or setting
it to anything other than a concrete dictionary object results in a
<code class="docutils literal notranslate"><span class="pre">TypeError</span></code>. If no function attributes have ever been set, the
functions <code class="docutils literal notranslate"><span class="pre">__dict__</span></code> will be empty.</p>
</section>
<section id="examples">
<h2><a class="toc-backref" href="#examples" role="doc-backlink">Examples</a></h2>
<p>Here are some examples of what you can do with this feature.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">a</span><span class="p">():</span>
<span class="k">pass</span>
<span class="n">a</span><span class="o">.</span><span class="n">publish</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">a</span><span class="o">.</span><span class="n">unittest</span> <span class="o">=</span> <span class="s1">&#39;&#39;&#39;...&#39;&#39;&#39;</span>
<span class="k">if</span> <span class="n">a</span><span class="o">.</span><span class="n">publish</span><span class="p">:</span>
<span class="nb">print</span> <span class="n">a</span><span class="p">()</span>
<span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="s1">&#39;unittest&#39;</span><span class="p">):</span>
<span class="n">testframework</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">a</span><span class="o">.</span><span class="n">unittest</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">C</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">a</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="s1">&#39;just a docstring&#39;</span>
<span class="n">a</span><span class="o">.</span><span class="n">publish</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">c</span> <span class="o">=</span> <span class="n">C</span><span class="p">()</span>
<span class="k">if</span> <span class="n">c</span><span class="o">.</span><span class="n">a</span><span class="o">.</span><span class="n">publish</span><span class="p">:</span>
<span class="n">publish</span><span class="p">(</span><span class="n">c</span><span class="o">.</span><span class="n">a</span><span class="p">())</span>
</pre></div>
</div>
<section id="other-uses">
<h3><a class="toc-backref" href="#other-uses" role="doc-backlink">Other Uses</a></h3>
<p>Paul Prescod enumerated a bunch of other uses on the <a class="reference external" href="https://mail.python.org/pipermail/python-dev/2000-April/003364.html">python-dev thread</a>.</p>
</section>
</section>
<section id="future-directions">
<h2><a class="toc-backref" href="#future-directions" role="doc-backlink">Future Directions</a></h2>
<p>Here are a number of future directions to consider. Any adoption
of these ideas would require a new PEP, which referenced this one,
and would have to be targeted at a Python version subsequent to
the 2.1 release.</p>
<ul>
<li>A previous version of this PEP allowed for both setter and
getter of attributes on unbound methods, and only getter on
bound methods. A number of problems were discovered with this
policy.<p>Because method attributes were stored in the underlying
function, this caused several potentially surprising results:</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">a</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="k">pass</span>
<span class="n">c1</span> <span class="o">=</span> <span class="n">C</span><span class="p">()</span>
<span class="n">c2</span> <span class="o">=</span> <span class="n">C</span><span class="p">()</span>
<span class="n">c1</span><span class="o">.</span><span class="n">a</span><span class="o">.</span><span class="n">publish</span> <span class="o">=</span> <span class="mi">1</span>
<span class="c1"># c2.a.publish would now be == 1 also!</span>
</pre></div>
</div>
<p>Because a change to <code class="docutils literal notranslate"><span class="pre">a</span></code> bound <code class="docutils literal notranslate"><span class="pre">c1</span></code> also caused a change to
<code class="docutils literal notranslate"><span class="pre">a</span></code> bound to <code class="docutils literal notranslate"><span class="pre">c2</span></code>, setting of attributes on bound methods
was disallowed. However, even allowing setting of attributes on
unbound methods has its ambiguities:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">D</span><span class="p">(</span><span class="n">C</span><span class="p">):</span> <span class="k">pass</span>
<span class="k">class</span> <span class="nc">E</span><span class="p">(</span><span class="n">C</span><span class="p">):</span> <span class="k">pass</span>
<span class="n">D</span><span class="o">.</span><span class="n">a</span><span class="o">.</span><span class="n">publish</span> <span class="o">=</span> <span class="mi">1</span>
<span class="c1"># E.a.publish would now be == 1 also!</span>
</pre></div>
</div>
<p>For this reason, the current PEP disallows setting attributes on
either bound or unbound methods, but does allow for getting
attributes on either both return the attribute value on the
underlying function object.</p>
<p>A future PEP might propose to implement setting (bound or
unbound) method attributes by setting attributes on the instance
or class, using special naming conventions. I.e.:</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">a</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="k">pass</span>
<span class="n">C</span><span class="o">.</span><span class="n">a</span><span class="o">.</span><span class="n">publish</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">C</span><span class="o">.</span><span class="n">__a_publish__</span> <span class="o">==</span> <span class="mi">1</span> <span class="c1"># true</span>
<span class="n">c</span> <span class="o">=</span> <span class="n">C</span><span class="p">()</span>
<span class="n">c</span><span class="o">.</span><span class="n">a</span><span class="o">.</span><span class="n">publish</span> <span class="o">=</span> <span class="mi">2</span>
<span class="n">c</span><span class="o">.</span><span class="n">__a_publish__</span> <span class="o">==</span> <span class="mi">2</span> <span class="c1"># true</span>
<span class="n">d</span> <span class="o">=</span> <span class="n">C</span><span class="p">()</span>
<span class="n">d</span><span class="o">.</span><span class="n">__a_publish__</span> <span class="o">==</span> <span class="mi">1</span> <span class="c1"># true</span>
</pre></div>
</div>
<p>Here, a lookup on the instance would look to the instances
dictionary first, followed by a lookup on the classs
dictionary, and finally a lookup on the function objects
dictionary.</p>
</li>
<li>Currently, Python supports function attributes only on Python
functions (i.e. those that are written in Python, not those that
are built-in). Should it be worthwhile, a separate patch can be
crafted that will add function attributes to built-ins.</li>
<li><code class="docutils literal notranslate"><span class="pre">__doc__</span></code> is the only function attribute that currently has
syntactic support for conveniently setting. It may be
worthwhile to eventually enhance the language for supporting
easy function attribute setting. Here are some syntaxes
suggested by PEP reviewers: <a class="footnote-reference brackets" href="#id6" id="id3">[3]</a><div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">a</span> <span class="p">{</span>
<span class="s1">&#39;publish&#39;</span> <span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
<span class="s1">&#39;unittest&#39;</span><span class="p">:</span> <span class="s1">&#39;&#39;&#39;...&#39;&#39;&#39;</span><span class="p">,</span>
<span class="p">}</span>
<span class="p">(</span><span class="n">args</span><span class="p">):</span>
<span class="c1"># ...</span>
<span class="k">def</span> <span class="nf">a</span><span class="p">(</span><span class="n">args</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;The usual docstring.&quot;&quot;&quot;</span>
<span class="p">{</span><span class="s1">&#39;publish&#39;</span> <span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
<span class="s1">&#39;unittest&#39;</span><span class="p">:</span> <span class="s1">&#39;&#39;&#39;...&#39;&#39;&#39;</span><span class="p">,</span>
<span class="c1"># etc.</span>
<span class="p">}</span>
<span class="k">def</span> <span class="nf">a</span><span class="p">(</span><span class="n">args</span><span class="p">)</span> <span class="n">having</span> <span class="p">(</span><span class="n">publish</span> <span class="o">=</span> <span class="mi">1</span><span class="p">):</span>
<span class="c1"># see reference [3]</span>
<span class="k">pass</span>
</pre></div>
</div>
<p>The BDFL is currently against any such special syntactic support
for setting arbitrary function attributes. Any syntax proposals
would have to be outlined in new PEPs.</p>
</li>
</ul>
</section>
<section id="dissenting-opinion">
<h2><a class="toc-backref" href="#dissenting-opinion" role="doc-backlink">Dissenting Opinion</a></h2>
<p>When this was discussed on the python-dev mailing list in April
2000, a number of dissenting opinions were voiced. For
completeness, the discussion thread starts on <a class="reference external" href="https://mail.python.org/pipermail/python-dev/2000-April/003361.html">python-dev</a>.</p>
<p>The dissenting arguments appear to fall under the following
categories:</p>
<ul class="simple">
<li>no clear purpose (what does it buy you?)</li>
<li>other ways to do it (e.g. mappings as class attributes)</li>
<li>useless until syntactic support is included</li>
</ul>
<p>Countering some of these arguments is the observation that with
vanilla Python 2.0, <code class="docutils literal notranslate"><span class="pre">__doc__</span></code> can in fact be set to any type of
object, so some semblance of writable function attributes are
already feasible. But that approach is yet another corruption of
<code class="docutils literal notranslate"><span class="pre">__doc__</span></code>.</p>
<p>And while it is of course possible to add mappings to class
objects (or in the case of function attributes, to the functions
module), it is more difficult and less obvious how to extract the
attribute values for inspection.</p>
<p>Finally, it may be desirable to add syntactic support, much the
same way that <code class="docutils literal notranslate"><span class="pre">__doc__</span></code> syntactic support exists. This can be
considered separately from the ability to actually set and get
function attributes.</p>
</section>
<section id="reference-implementation">
<h2><a class="toc-backref" href="#reference-implementation" role="doc-backlink">Reference Implementation</a></h2>
<p>This PEP has been accepted and the implementation has been
integrated into Python 2.1.</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="id4" role="doc-footnote">
<dt class="label" id="id4">[<a href="#id1">1</a>]</dt>
<dd>Aycock, “Compiling Little Languages in Python”,
<a class="reference external" href="https://legacy.python.org/workshops/1998-11/proceedings/papers/aycock-little/aycock-little.html">https://legacy.python.org/workshops/1998-11/proceedings/papers/aycock-little/aycock-little.html</a></aside>
<aside class="footnote brackets" id="id5" role="doc-footnote">
<dt class="label" id="id5">[<a href="#id2">2</a>]</dt>
<dd><a class="reference external" href="https://web.archive.org/web/20010307022153/http://classic.zope.org:8080/Documentation/Reference/ORB">https://web.archive.org/web/20010307022153/http://classic.zope.org:8080/Documentation/Reference/ORB</a></aside>
<aside class="footnote brackets" id="id6" role="doc-footnote">
<dt class="label" id="id6">[<a href="#id3">3</a>]</dt>
<dd>Hudson, Michael, SourceForge patch implementing this syntax,
<a class="reference external" href="https://web.archive.org/web/20010901050535/http://sourceforge.net/tracker/index.php?func=detail&amp;aid=403441&amp;group_id=5470&amp;atid=305470">https://web.archive.org/web/20010901050535/http://sourceforge.net/tracker/index.php?func=detail&amp;aid=403441&amp;group_id=5470&amp;atid=305470</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-0232.rst">https://github.com/python/peps/blob/main/peps/pep-0232.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0232.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="#introduction">Introduction</a></li>
<li><a class="reference internal" href="#background">Background</a></li>
<li><a class="reference internal" href="#proposal">Proposal</a></li>
<li><a class="reference internal" href="#examples">Examples</a><ul>
<li><a class="reference internal" href="#other-uses">Other Uses</a></li>
</ul>
</li>
<li><a class="reference internal" href="#future-directions">Future Directions</a></li>
<li><a class="reference internal" href="#dissenting-opinion">Dissenting Opinion</a></li>
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</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-0232.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>