CINXE.COM
PEP 457 – Notation For Positional-Only Parameters | peps.python.org
<!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 457 – Notation For Positional-Only Parameters | peps.python.org</title> <link rel="shortcut icon" href="../_static/py.png"> <link rel="canonical" href="https://peps.python.org/pep-0457/"> <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 457 – Notation For Positional-Only Parameters | 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-0457/"> <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 457</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 457 – Notation For Positional-Only Parameters</h1> <dl class="rfc2822 field-list simple"> <dt class="field-odd">Author<span class="colon">:</span></dt> <dd class="field-odd">Larry Hastings <larry at hastings.org></dd> <dt class="field-even">Discussions-To<span class="colon">:</span></dt> <dd class="field-even"><a class="reference external" href="https://mail.python.org/archives/list/python-dev@python.org/">Python-Dev list</a></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="Non-normative PEP containing background, guidelines or other information relevant to the Python ecosystem">Informational</abbr></dd> <dt class="field-odd">Created<span class="colon">:</span></dt> <dd class="field-odd">08-Oct-2013</dd> </dl> <hr class="docutils" /> <section id="contents"> <details><summary>Table of Contents</summary><ul class="simple"> <li><a class="reference internal" href="#overview">Overview</a></li> <li><a class="reference internal" href="#rationale">Rationale</a><ul> <li><a class="reference internal" href="#positional-only-parameter-semantics-in-current-python">Positional-Only Parameter Semantics In Current Python</a></li> </ul> </li> <li><a class="reference internal" href="#motivation">Motivation</a></li> <li><a class="reference internal" href="#the-current-state-of-documentation-for-positional-only-parameters">The Current State Of Documentation For Positional-Only Parameters</a></li> <li><a class="reference internal" href="#syntax-and-semantics">Syntax And Semantics</a></li> <li><a class="reference internal" href="#additional-limitations">Additional Limitations</a></li> <li><a class="reference internal" href="#notes-for-a-future-implementor">Notes For A Future Implementor</a></li> <li><a class="reference internal" href="#unresolved-questions">Unresolved Questions</a></li> <li><a class="reference internal" href="#thanks">Thanks</a></li> <li><a class="reference internal" href="#copyright">Copyright</a></li> </ul> </details></section> <section id="overview"> <h2><a class="toc-backref" href="#overview" role="doc-backlink">Overview</a></h2> <p>This PEP proposes a notation for positional-only parameters in Python. Positional-only parameters are parameters without an externally-usable name; when a function accepting positional-only parameters is called, positional arguments are mapped to these parameters based solely on their position.</p> <p>This PEP is an Informational PEP describing the notation for use when describing APIs that use positional-only parameters (e.g. in Argument Clinic, or in the string representation of <code class="docutils literal notranslate"><span class="pre">inspect.Signature</span></code> objects). A separate PEP, <a class="pep reference internal" href="../pep-0570/" title="PEP 570 – Python Positional-Only Parameters">PEP 570</a>, proposes elevation of this notation to full Python syntax.</p> </section> <section id="rationale"> <h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2> <p>Python has always supported positional-only parameters. Early versions of Python lacked the concept of specifying parameters by name, so naturally all parameters were positional-only. This changed around Python 1.0, when all parameters suddenly became positional-or-keyword. But, even in current versions of Python, many CPython “builtin” functions still only accept positional-only arguments.</p> <p>Functions implemented in modern Python can accept an arbitrary number of positional-only arguments, via the variadic <code class="docutils literal notranslate"><span class="pre">*args</span></code> parameter. However, there is no Python syntax to specify accepting a specific number of positional-only parameters. Put another way, there are many builtin functions whose signatures are simply not expressible with Python syntax.</p> <p>This PEP proposes a notation for such signatures that could form the basis of a backwards-compatible syntax that should permit implementing any builtin in pure Python code (see <a class="pep reference internal" href="../pep-0570/" title="PEP 570 – Python Positional-Only Parameters">PEP 570</a> for that proposal).</p> <section id="positional-only-parameter-semantics-in-current-python"> <h3><a class="toc-backref" href="#positional-only-parameter-semantics-in-current-python" role="doc-backlink">Positional-Only Parameter Semantics In Current Python</a></h3> <p>There are many, many examples of builtins that only accept positional-only parameters. The resulting semantics are easily experienced by the Python programmer–just try calling one, specifying its arguments by name:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="nb">pow</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">y</span><span class="o">=</span><span class="mi">3</span><span class="p">)</span> <span class="gt">Traceback (most recent call last):</span> File <span class="nb">"<stdin>"</span>, line <span class="m">1</span>, in <span class="n"><module></span> <span class="gr">TypeError</span>: <span class="n">pow() takes no keyword arguments</span> </pre></div> </div> <p>In addition, there are some functions with particularly interesting semantics:</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">range()</span></code>, which accepts an optional parameter to the <em>left</em> of its required parameter. <a class="footnote-reference brackets" href="#range" id="id1">[2]</a></li> <li><code class="docutils literal notranslate"><span class="pre">dict()</span></code>, whose mapping/iterator parameter is optional and semantically must be positional-only. Any externally visible name for this parameter would occlude that name going into the <code class="docutils literal notranslate"><span class="pre">**kwarg</span></code> keyword variadic parameter dict! <a class="footnote-reference brackets" href="#dict" id="id2">[1]</a></li> </ul> <p>Obviously one can simulate any of these in pure Python code by accepting <code class="docutils literal notranslate"><span class="pre">(*args,</span> <span class="pre">**kwargs)</span></code> and parsing the arguments by hand. But this results in a disconnect between the Python function’s signature and what it actually accepts, not to mention the work of implementing said argument parsing.</p> </section> </section> <section id="motivation"> <h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2> <p>This PEP does not propose we implement positional-only parameters in Python. The goal of this PEP is simply to define the syntax, so that:</p> <ul class="simple"> <li>Documentation can clearly, unambiguously, and consistently express exactly how the arguments for a function will be interpreted.</li> <li>The syntax is reserved for future use, in case the community decides someday to add positional-only parameters to the language.</li> <li>Argument Clinic can use a variant of the syntax as part of its input when defining the arguments for built-in functions.</li> </ul> </section> <section id="the-current-state-of-documentation-for-positional-only-parameters"> <h2><a class="toc-backref" href="#the-current-state-of-documentation-for-positional-only-parameters" role="doc-backlink">The Current State Of Documentation For Positional-Only Parameters</a></h2> <p>The documentation for positional-only parameters is incomplete and inconsistent:</p> <ul class="simple"> <li>Some functions denote optional <em>groups</em> of positional-only arguments by enclosing them in nested square brackets. <a class="footnote-reference brackets" href="#border" id="id3">[3]</a></li> <li>Some functions denote optional groups of positional-only arguments by presenting multiple prototypes with varying numbers of arguments. <a class="footnote-reference brackets" href="#sendfile" id="id4">[4]</a></li> <li>Some functions use <em>both</em> of the above approaches. <a class="footnote-reference brackets" href="#range" id="id5">[2]</a> <a class="footnote-reference brackets" href="#addch" id="id6">[5]</a></li> </ul> <p>One more important idea to consider: currently in the documentation there’s no way to tell whether a function takes positional-only parameters. <code class="docutils literal notranslate"><span class="pre">open()</span></code> accepts keyword arguments, <code class="docutils literal notranslate"><span class="pre">ord()</span></code> does not, but there is no way of telling just by reading the documentation that this is true.</p> </section> <section id="syntax-and-semantics"> <h2><a class="toc-backref" href="#syntax-and-semantics" role="doc-backlink">Syntax And Semantics</a></h2> <p>From the “ten-thousand foot view”, and ignoring <code class="docutils literal notranslate"><span class="pre">*args</span></code> and <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> for now, the grammar for a function definition currently looks like this:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">name</span><span class="p">(</span><span class="n">positional_or_keyword_parameters</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">keyword_only_parameters</span><span class="p">):</span> </pre></div> </div> <p>Building on that perspective, the new syntax for functions would look like this:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">name</span><span class="p">(</span><span class="n">positional_only_parameters</span><span class="p">,</span> <span class="o">/</span><span class="p">,</span> <span class="n">positional_or_keyword_parameters</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">keyword_only_parameters</span><span class="p">):</span> </pre></div> </div> <p>All parameters before the <code class="docutils literal notranslate"><span class="pre">/</span></code> are positional-only. If <code class="docutils literal notranslate"><span class="pre">/</span></code> is not specified in a function signature, that function does not accept any positional-only parameters.</p> <p>Positional-only parameters can have a default value, and if they do they are optional. Positional-only parameters that don’t have a default value are “required” positional-only parameters.</p> <p>More semantics of positional-only parameters:</p> <ul class="simple"> <li>Although positional-only parameter technically have names, these names are internal-only; positional-only parameters are <em>never</em> externally addressable by name. (Similarly to <code class="docutils literal notranslate"><span class="pre">*args</span></code> and <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code>.)</li> <li>If there are arguments after the <code class="docutils literal notranslate"><span class="pre">/</span></code>, then you must specify a comma after the <code class="docutils literal notranslate"><span class="pre">/</span></code>, just as there is a comma after the <code class="docutils literal notranslate"><span class="pre">*</span></code> denoting the shift to keyword-only parameters.</li> <li>This syntax has no effect on <code class="docutils literal notranslate"><span class="pre">*args</span></code> or <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code>.</li> </ul> </section> <section id="additional-limitations"> <h2><a class="toc-backref" href="#additional-limitations" role="doc-backlink">Additional Limitations</a></h2> <p>Argument Clinic uses a form of this syntax for specifying builtins. It imposes further limitations that are theoretically unnecessary but make the implementation easier. Specifically:</p> <ul class="simple"> <li>A function that has positional-only parameters currently cannot have any other kind of parameter. (This will probably be relaxed slightly in the near future.)</li> <li>Argument Clinic supports an additional syntax called “optional groups”. An “optional group” is a sequential set of positional-only parameters that must be specified or not-specified as a group. If, for example, you define a function in Argument Clinic that takes four parameters, and all of them are positional-only and in one optional group, then when calling the function you must specify either zero arguments or four arguments. This is necessary to cover more of Python’s legacy library, but is outside the scope of this PEP, and is not recommended for actual inclusion in the Python language.</li> </ul> </section> <section id="notes-for-a-future-implementor"> <h2><a class="toc-backref" href="#notes-for-a-future-implementor" role="doc-backlink">Notes For A Future Implementor</a></h2> <p>If we decide to implement positional-only parameters in a future version of Python, we’d have to do some additional work to preserve their semantics. The problem: how do we inform a parameter that no value was passed in for it when the function was called?</p> <p>The obvious solution: add a new singleton constant to Python that is passed in when a parameter is not mapped to an argument. I propose that the value be called <code class="docutils literal notranslate"><span class="pre">undefined</span></code>, and be a singleton of a special class called <code class="docutils literal notranslate"><span class="pre">Undefined</span></code>. If a positional-only parameter did not receive an argument when called, its value would be set to <code class="docutils literal notranslate"><span class="pre">undefined</span></code>.</p> <p>But this raises a further problem. How do can we tell the difference between “this positional-only parameter did not receive an argument” and “the caller passed in <code class="docutils literal notranslate"><span class="pre">undefined</span></code> for this parameter”?</p> <p>It’d be nice to make it illegal to pass <code class="docutils literal notranslate"><span class="pre">undefined</span></code> in as an argument to a function–to, say, raise an exception. But that would slow Python down, and the “consenting adults” rule appears applicable here. So making it illegal should probably be strongly discouraged but not outright prevented.</p> <p>However, it should be allowed (and encouraged) for user functions to specify <code class="docutils literal notranslate"><span class="pre">undefined</span></code> as a default value for parameters.</p> </section> <section id="unresolved-questions"> <h2><a class="toc-backref" href="#unresolved-questions" role="doc-backlink">Unresolved Questions</a></h2> <p>There are three types of parameters in Python:</p> <ol class="arabic simple"> <li>positional-only parameters,</li> <li>positional-or-keyword parameters, and</li> <li>keyword-only parameters.</li> </ol> <p>Python allows functions to have both 2 and 3. And some builtins (e.g. range) have both 1 and 3. Does it make sense to have functions that have both 1 and 2? Or all of the above?</p> </section> <section id="thanks"> <h2><a class="toc-backref" href="#thanks" role="doc-backlink">Thanks</a></h2> <p>Credit for the use of ‘/’ as the separator between positional-only and positional-or-keyword parameters goes to Guido van Rossum, in a proposal from 2012. <a class="footnote-reference brackets" href="#guido" id="id7">[6]</a></p> <p>Credit for making left option groups higher precedence goes to Alyssa Coghlan. (Conversation in person at PyCon US 2013.)</p> <aside class="footnote-list brackets"> <aside class="footnote brackets" id="dict" role="doc-footnote"> <dt class="label" id="dict">[<a href="#id2">1</a>]</dt> <dd><a class="reference external" href="http://docs.python.org/3/library/stdtypes.html#dict">http://docs.python.org/3/library/stdtypes.html#dict</a></aside> <aside class="footnote brackets" id="range" role="doc-footnote"> <dt class="label" id="range">[2]<em> (<a href='#id1'>1</a>, <a href='#id5'>2</a>) </em></dt> <dd><a class="reference external" href="http://docs.python.org/3/library/functions.html#func-range">http://docs.python.org/3/library/functions.html#func-range</a></aside> <aside class="footnote brackets" id="border" role="doc-footnote"> <dt class="label" id="border">[<a href="#id3">3</a>]</dt> <dd><a class="reference external" href="http://docs.python.org/3/library/curses.html#curses.window.border">http://docs.python.org/3/library/curses.html#curses.window.border</a></aside> <aside class="footnote brackets" id="sendfile" role="doc-footnote"> <dt class="label" id="sendfile">[<a href="#id4">4</a>]</dt> <dd><a class="reference external" href="http://docs.python.org/3/library/os.html#os.sendfile">http://docs.python.org/3/library/os.html#os.sendfile</a></aside> <aside class="footnote brackets" id="addch" role="doc-footnote"> <dt class="label" id="addch">[<a href="#id6">5</a>]</dt> <dd><a class="reference external" href="http://docs.python.org/3/library/curses.html#curses.window.addch">http://docs.python.org/3/library/curses.html#curses.window.addch</a></aside> <aside class="footnote brackets" id="guido" role="doc-footnote"> <dt class="label" id="guido">[<a href="#id7">6</a>]</dt> <dd>Guido van Rossum, posting to python-ideas, March 2012: <a class="reference external" href="https://mail.python.org/pipermail/python-ideas/2012-March/014364.html">https://mail.python.org/pipermail/python-ideas/2012-March/014364.html</a> and <a class="reference external" href="https://mail.python.org/pipermail/python-ideas/2012-March/014378.html">https://mail.python.org/pipermail/python-ideas/2012-March/014378.html</a> and <a class="reference external" href="https://mail.python.org/pipermail/python-ideas/2012-March/014417.html">https://mail.python.org/pipermail/python-ideas/2012-March/014417.html</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-0457.rst">https://github.com/python/peps/blob/main/peps/pep-0457.rst</a></p> <p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0457.rst">2025-02-01 08:59:27 GMT</a></p> </article> <nav id="pep-sidebar"> <h2>Contents</h2> <ul> <li><a class="reference internal" href="#overview">Overview</a></li> <li><a class="reference internal" href="#rationale">Rationale</a><ul> <li><a class="reference internal" href="#positional-only-parameter-semantics-in-current-python">Positional-Only Parameter Semantics In Current Python</a></li> </ul> </li> <li><a class="reference internal" href="#motivation">Motivation</a></li> <li><a class="reference internal" href="#the-current-state-of-documentation-for-positional-only-parameters">The Current State Of Documentation For Positional-Only Parameters</a></li> <li><a class="reference internal" href="#syntax-and-semantics">Syntax And Semantics</a></li> <li><a class="reference internal" href="#additional-limitations">Additional Limitations</a></li> <li><a class="reference internal" href="#notes-for-a-future-implementor">Notes For A Future Implementor</a></li> <li><a class="reference internal" href="#unresolved-questions">Unresolved Questions</a></li> <li><a class="reference internal" href="#thanks">Thanks</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-0457.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>