python-peps/pep-0614/index.html

326 lines
22 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 614 Relaxing Grammar Restrictions On Decorators | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-0614/">
<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 614 Relaxing Grammar Restrictions On Decorators | peps.python.org'>
<meta property="og:description" content="Python currently requires that all decorators consist of a dotted name, optionally followed by a single call. This PEP proposes removing these limitations and allowing decorators to be any valid expression.">
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-0614/">
<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 currently requires that all decorators consist of a dotted name, optionally followed by a single call. This PEP proposes removing these limitations and allowing decorators to be any valid expression.">
<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 614</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 614 Relaxing Grammar Restrictions On Decorators</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Brandt Bucher &lt;brandt&#32;&#97;t&#32;python.org&gt;</dd>
<dt class="field-even">Sponsor<span class="colon">:</span></dt>
<dd class="field-even">Guido van Rossum &lt;guido&#32;&#97;t&#32;python.org&gt;</dd>
<dt class="field-odd">Status<span class="colon">:</span></dt>
<dd class="field-odd"><abbr title="Accepted and implementation complete, or no longer active">Final</abbr></dd>
<dt class="field-even">Type<span class="colon">:</span></dt>
<dd class="field-even"><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-odd">Created<span class="colon">:</span></dt>
<dd class="field-odd">10-Feb-2020</dd>
<dt class="field-even">Python-Version<span class="colon">:</span></dt>
<dd class="field-even">3.9</dd>
<dt class="field-odd">Post-History<span class="colon">:</span></dt>
<dd class="field-odd">11-Feb-2020, 18-Feb-2020, 03-Mar-2020</dd>
<dt class="field-even">Resolution<span class="colon">:</span></dt>
<dd class="field-even"><a class="reference external" href="https://mail.python.org/archives/list/python-dev&#64;python.org/thread/VSR66MOTCDCY7ZFH4IG7QVFI2JXQQZQ5">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></li>
<li><a class="reference internal" href="#rationale">Rationale</a><ul>
<li><a class="reference internal" href="#allowing-any-expression">Allowing Any Expression</a></li>
<li><a class="reference internal" href="#what-counts-as-an-expression">What Counts As An “Expression”</a><ul>
<li><a class="reference internal" href="#tuple-displays-must-be-parenthesized">Tuple Displays <em>Must</em> Be Parenthesized</a></li>
<li><a class="reference internal" href="#named-expressions-need-not-be-parenthesized">Named Expressions <em>Need Not</em> Be Parenthesized</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#specification">Specification</a></li>
<li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a></li>
<li><a class="reference internal" href="#how-to-teach-this">How To Teach This</a></li>
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
</details></section>
<section id="abstract">
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
<p>Python currently requires that all decorators consist of a dotted
name, optionally followed by a single call. This PEP proposes removing
these limitations and allowing decorators to be any valid expression.</p>
</section>
<section id="motivation">
<h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2>
<p>When decorators were first being introduced, <a class="reference external" href="https://mail.python.org/archives/list/python-dev&#64;python.org/message/P3JD24UFFPZUUDANOAI6GZAPIGY4CVK7">Guido described</a>
the motivation to limit their syntax as a preference, not a technical
requirement:</p>
<blockquote>
<div>I have a gut feeling about this one. Im not sure where it comes
from, but I have it… So while it would be quite easy to change
the syntax to <code class="docutils literal notranslate"><span class="pre">&#64;test</span></code> in the future, Id like to stick to with
the more restricted form unless a real use case is presented where
allowing <code class="docutils literal notranslate"><span class="pre">&#64;test</span></code> would increase readability.</div></blockquote>
<p>While these limitations were rarely encountered in practice, <a class="reference external" href="https://bugs.python.org/issue19660">BPO
issues</a> and <a class="reference external" href="https://mail.python.org/archives/list/python-ideas&#64;python.org/thread/UQOCJH3KOPBP7P3AVNS3OYBGZPR3V2WO/#CAOXYF4GV76AFJNCYSYMQTBM7CIPPH5M">mailing list posts</a>
have consistently surfaced over the years requesting that they be
removed. The <a class="reference external" href="https://mail.python.org/archives/list/python-ideas&#64;python.org/thread/WOWD4P323DYDIGUQVWMESDWUG6QOW4MP">most recent one</a>
(which <a class="reference external" href="https://mail.python.org/archives/list/python-ideas&#64;python.org/message/FKE7ZFGUDCU5WVOE2QTD5XGMCNCOMETV">prompted this proposal</a>)
contained a good example of code using the <code class="docutils literal notranslate"><span class="pre">PyQt5</span></code> library that
would become more readable, idiomatic, and maintainable if the
existing restrictions were relaxed. Slightly modified:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">buttons</span> <span class="o">=</span> <span class="p">[</span><span class="n">QPushButton</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;Button </span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s1">&#39;</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">)]</span>
<span class="c1"># Do stuff with the list of buttons...</span>
<span class="nd">@buttons</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">clicked</span><span class="o">.</span><span class="n">connect</span>
<span class="k">def</span> <span class="nf">spam</span><span class="p">():</span>
<span class="o">...</span>
<span class="nd">@buttons</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">clicked</span><span class="o">.</span><span class="n">connect</span>
<span class="k">def</span> <span class="nf">eggs</span><span class="p">():</span>
<span class="o">...</span>
<span class="c1"># Do stuff with the list of buttons...</span>
</pre></div>
</div>
<p>Currently, these decorations must be rewritten as something like:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">button_0</span> <span class="o">=</span> <span class="n">buttons</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="nd">@button_0</span><span class="o">.</span><span class="n">clicked</span><span class="o">.</span><span class="n">connect</span>
<span class="k">def</span> <span class="nf">spam</span><span class="p">():</span>
<span class="o">...</span>
<span class="n">button_1</span> <span class="o">=</span> <span class="n">buttons</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="nd">@button_1</span><span class="o">.</span><span class="n">clicked</span><span class="o">.</span><span class="n">connect</span>
<span class="k">def</span> <span class="nf">eggs</span><span class="p">():</span>
<span class="o">...</span>
</pre></div>
</div>
<p>Further, the current grammar is already loose enough that its trivial
to hack more complicated decorator expressions together. So rather
than disallow arbitrarily complex expressions, as intended, the
current restrictions only make them uglier and less efficient:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Identity function hack:</span>
<span class="k">def</span> <span class="nf">_</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
<span class="k">return</span> <span class="n">x</span>
<span class="nd">@_</span><span class="p">(</span><span class="n">buttons</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">clicked</span><span class="o">.</span><span class="n">connect</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">spam</span><span class="p">():</span>
<span class="o">...</span>
<span class="c1"># eval hack:</span>
<span class="nd">@eval</span><span class="p">(</span><span class="s2">&quot;buttons[1].clicked.connect&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">eggs</span><span class="p">():</span>
<span class="o">...</span>
</pre></div>
</div>
</section>
<section id="rationale">
<h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2>
<section id="allowing-any-expression">
<h3><a class="toc-backref" href="#allowing-any-expression" role="doc-backlink">Allowing Any Expression</a></h3>
<p>The decision to allow <em>any</em> valid expression (and not just relaxing
the current restrictions to allow, for example, subscripting) has
been considered as the next logical step in the evolution of decorator
grammar for quite some time. As <a class="reference external" href="https://mail.python.org/archives/list/python-ideas&#64;python.org/message/CAOXYF4GV76AFJNCYSYMQTBM7CIPPH5M">Guido noted</a>,
during yet another mailing list thread:</p>
<blockquote>
<div>I dont think its reasonable to constrain it less than it
currently is but more than a general expression.</div></blockquote>
<p>Special-casing the grammar to allow <em>some</em> useful cases would only
complicate the current situation, and all but guarantee that the
process would repeat itself sometime in the future. Further, one
purpose of this grammatical change is to discourage the temptation to
use hacks like the <code class="docutils literal notranslate"><span class="pre">eval</span></code> and identity-function anti-patterns shown
above.</p>
<p>In short: if were removing somewhat arbitrary restrictions, we should
remove <em>all</em> of them.</p>
</section>
<section id="what-counts-as-an-expression">
<h3><a class="toc-backref" href="#what-counts-as-an-expression" role="doc-backlink">What Counts As An “Expression”</a></h3>
<p>Throughout this document, the word “expression” is used as defined in
the <a class="reference external" href="https://docs.python.org/3.9/reference/expressions.html#grammar-token-expression">Python Language Reference</a>.
This can be summarized as “anything thats valid as a test in <code class="docutils literal notranslate"><span class="pre">if</span></code>,
<code class="docutils literal notranslate"><span class="pre">elif</span></code>, and <code class="docutils literal notranslate"><span class="pre">while</span></code> blocks”. This differs subtly from a perhaps
more popular <a class="reference external" href="https://docs.python.org/3/glossary.html#term-expression">definition</a>, which can
be summarized as “anything thats valid as string input to <code class="docutils literal notranslate"><span class="pre">eval</span></code>”.</p>
<p>This definition of “expression” is convenient in that it fits our
needs well, and reuses the allowed grammar of existing language
constructs. It has two subtle differences from the other definition:</p>
<section id="tuple-displays-must-be-parenthesized">
<h4><a class="toc-backref" href="#tuple-displays-must-be-parenthesized" role="doc-backlink">Tuple Displays <em>Must</em> Be Parenthesized</a></h4>
<p>This is based on an observation Guido made in the same email.
Continued immediately from above:</p>
<blockquote>
<div>Though I wouldnt allow commas theres no way that<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@f</span><span class="p">,</span> <span class="n">g</span>
<span class="k">def</span> <span class="nf">pooh</span><span class="p">():</span> <span class="o">...</span>
</pre></div>
</div>
<p>can make sense.</p>
</div></blockquote>
<p>Indeed, it may even lead inexperienced readers to conclude that
several decorators are being applied, as if they were stacked.
Requiring parentheses here makes the (admittedly nonsensical) intent
clear without imposing further restrictions and grammar complications.</p>
</section>
<section id="named-expressions-need-not-be-parenthesized">
<h4><a class="toc-backref" href="#named-expressions-need-not-be-parenthesized" role="doc-backlink">Named Expressions <em>Need Not</em> Be Parenthesized</a></h4>
<p>Here, the choice of syntax is unambiguous. <a class="pep reference internal" href="../pep-0572/" title="PEP 572 Assignment Expressions">PEP 572</a> explains
why it requires parentheses around top-level expression statements:</p>
<blockquote>
<div>This rule is included to simplify the choice for the user between
an assignment statement and an assignment expression there is
no syntactic position where both are valid.</div></blockquote>
<p>Since an assignment statement is not valid here, assignment
expressions should not be unnecessarily burdened with parentheses.</p>
</section>
</section>
</section>
<section id="specification">
<h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2>
<p>The grammar for decorators is currently:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">decorator</span><span class="p">:</span> <span class="s1">&#39;@&#39;</span> <span class="n">dotted_name</span> <span class="p">[</span> <span class="s1">&#39;(&#39;</span> <span class="p">[</span><span class="n">arglist</span><span class="p">]</span> <span class="s1">&#39;)&#39;</span> <span class="p">]</span> <span class="n">NEWLINE</span>
</pre></div>
</div>
<p>This PEP proposes that it be simplified to:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">decorator</span><span class="p">:</span> <span class="s1">&#39;@&#39;</span> <span class="n">namedexpr_test</span> <span class="n">NEWLINE</span>
</pre></div>
</div>
</section>
<section id="backwards-compatibility">
<h2><a class="toc-backref" href="#backwards-compatibility" role="doc-backlink">Backwards Compatibility</a></h2>
<p>This new grammar is fully backward-compatible with the existing
grammar.</p>
</section>
<section id="how-to-teach-this">
<h2><a class="toc-backref" href="#how-to-teach-this" role="doc-backlink">How To Teach This</a></h2>
<p>Decorators can continue to be taught as they always have; the average
Python programmer is likely unaware that the current restriction even
exists.</p>
</section>
<section id="reference-implementation">
<h2><a class="toc-backref" href="#reference-implementation" role="doc-backlink">Reference Implementation</a></h2>
<p>The author has written a <a class="reference external" href="https://github.com/python/cpython/pull/18570">CPython implementation</a>.</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-0614.rst">https://github.com/python/peps/blob/main/peps/pep-0614.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0614.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="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#motivation">Motivation</a></li>
<li><a class="reference internal" href="#rationale">Rationale</a><ul>
<li><a class="reference internal" href="#allowing-any-expression">Allowing Any Expression</a></li>
<li><a class="reference internal" href="#what-counts-as-an-expression">What Counts As An “Expression”</a><ul>
<li><a class="reference internal" href="#tuple-displays-must-be-parenthesized">Tuple Displays <em>Must</em> Be Parenthesized</a></li>
<li><a class="reference internal" href="#named-expressions-need-not-be-parenthesized">Named Expressions <em>Need Not</em> Be Parenthesized</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#specification">Specification</a></li>
<li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a></li>
<li><a class="reference internal" href="#how-to-teach-this">How To Teach This</a></li>
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</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-0614.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>