CINXE.COM

PEP 570 – Python 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 570 – Python Positional-Only Parameters | peps.python.org</title> <link rel="shortcut icon" href="../_static/py.png"> <link rel="canonical" href="https://peps.python.org/pep-0570/"> <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 570 – Python Positional-Only Parameters | peps.python.org'> <meta property="og:description" content="This PEP proposes to introduce a new syntax, /, for specifying positional-only parameters in Python function definitions."> <meta property="og:type" content="website"> <meta property="og:url" content="https://peps.python.org/pep-0570/"> <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 proposes to introduce a new syntax, /, for specifying positional-only parameters in Python function definitions."> <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 570</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 570 – Python 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 &lt;larry&#32;&#97;t&#32;hastings.org&gt;, Pablo Galindo &lt;pablogsal&#32;&#97;t&#32;python.org&gt;, Mario Corchero &lt;mariocj89&#32;&#97;t&#32;gmail.com&gt;, Eric N. Vander Weele &lt;ericvw&#32;&#97;t&#32;gmail.com&gt;</dd> <dt class="field-even">BDFL-Delegate<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">Discussions-To<span class="colon">:</span></dt> <dd class="field-odd"><a class="reference external" href="https://discuss.python.org/t/pep-570-python-positional-only-parameters/1078">Discourse thread</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">Created<span class="colon">:</span></dt> <dd class="field-even">20-Jan-2018</dd> <dt class="field-odd">Python-Version<span class="colon">:</span></dt> <dd class="field-odd">3.8</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="#history-of-positional-only-parameter-semantics-in-python">History of Positional-Only Parameter Semantics in Python</a></li> <li><a class="reference internal" href="#problems-without-positional-only-parameters">Problems Without Positional-Only Parameters</a><ul> <li><a class="reference internal" href="#challenges-for-library-authors">Challenges for Library Authors</a></li> <li><a class="reference internal" href="#challenges-for-users-of-an-api">Challenges for Users of an API</a></li> </ul> </li> <li><a class="reference internal" href="#benefits-of-positional-only-parameters">Benefits of Positional-Only Parameters</a><ul> <li><a class="reference internal" href="#empowering-library-authors">Empowering Library Authors</a></li> <li><a class="reference internal" href="#improving-language-consistency">Improving Language Consistency</a></li> </ul> </li> </ul> </li> <li><a class="reference internal" href="#rationale">Rationale</a><ul> <li><a class="reference internal" href="#performance">Performance</a></li> <li><a class="reference internal" href="#maintainability">Maintainability</a></li> <li><a class="reference internal" href="#logical-ordering">Logical ordering</a></li> <li><a class="reference internal" href="#compatibility-for-pure-python-and-c-modules">Compatibility for Pure Python and C Modules</a></li> <li><a class="reference internal" href="#consistency-in-subclasses">Consistency in Subclasses</a></li> <li><a class="reference internal" href="#optimizations">Optimizations</a></li> </ul> </li> <li><a class="reference internal" href="#specification">Specification</a><ul> <li><a class="reference internal" href="#syntax-and-semantics">Syntax and Semantics</a></li> <li><a class="reference internal" href="#full-grammar-specification">Full Grammar Specification</a></li> <li><a class="reference internal" href="#semantic-corner-case">Semantic Corner Case</a></li> <li><a class="reference internal" href="#origin-of-as-a-separator">Origin of “/” as a Separator</a></li> </ul> </li> <li><a class="reference internal" href="#how-to-teach-this">How To Teach This</a><ul> <li><a class="reference internal" href="#positional-or-keyword-arguments">Positional-or-Keyword Arguments</a></li> <li><a class="reference internal" href="#positional-only-parameters">Positional-Only Parameters</a></li> <li><a class="reference internal" href="#keyword-only-arguments">Keyword-Only Arguments</a></li> <li><a class="reference internal" href="#function-examples">Function Examples</a></li> <li><a class="reference internal" href="#recap">Recap</a></li> </ul> </li> <li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li> <li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul> <li><a class="reference internal" href="#do-nothing">Do Nothing</a></li> <li><a class="reference internal" href="#decorators">Decorators</a></li> <li><a class="reference internal" href="#per-argument-marker">Per-Argument Marker</a></li> <li><a class="reference internal" href="#using-as-a-per-argument-marker">Using “__” as a Per-Argument Marker</a></li> <li><a class="reference internal" href="#group-positional-only-parameters-with-parentheses">Group Positional-Only Parameters With Parentheses</a></li> <li><a class="reference internal" href="#after-separator-proposal">After Separator Proposal</a></li> </ul> </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="abstract"> <h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2> <p>This PEP proposes to introduce a new syntax, <code class="docutils literal notranslate"><span class="pre">/</span></code>, for specifying positional-only parameters in Python function definitions.</p> <p>Positional-only parameters have no externally-usable name. When a function accepting positional-only parameters is called, positional arguments are mapped to these parameters based solely on their order.</p> <p>When designing APIs (application programming interfaces), library authors try to ensure correct and intended usage of an API. Without the ability to specify which parameters are positional-only, library authors must be careful when choosing appropriate parameter names. This care must be taken even for required parameters or when the parameters have no external semantic meaning for callers of the API.</p> <p>In this PEP, we discuss:</p> <ul class="simple"> <li>Python’s history and current semantics for positional-only parameters</li> <li>the problems encountered by not having them</li> <li>how these problems are handled without language-intrinsic support for positional-only parameters</li> <li>the benefits of having positional-only parameters</li> </ul> <p>Within context of the motivation, we then:</p> <ul class="simple"> <li>discuss why positional-only parameters should be a feature intrinsic to the language</li> <li>propose the syntax for marking positional-only parameters</li> <li>present how to teach this new feature</li> <li>note rejected ideas in further detail</li> </ul> </section> <section id="motivation"> <h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2> <section id="history-of-positional-only-parameter-semantics-in-python"> <h3><a class="toc-backref" href="#history-of-positional-only-parameter-semantics-in-python" role="doc-backlink">History of Positional-Only Parameter Semantics in Python</a></h3> <p>Python originally supported positional-only parameters. Early versions of the language lacked the ability to call functions with arguments bound to parameters by name. Around Python 1.0, parameter semantics changed to be positional-or-keyword. Since then, users have been able to provide arguments to a function either positionally or by the keyword name specified in the function’s definition.</p> <p>In current versions of Python, many CPython “builtin” and standard library functions only accept positional-only parameters. The resulting semantics can be easily observed by calling one of these functions using keyword arguments:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">help</span><span class="p">(</span><span class="nb">pow</span><span class="p">)</span> <span class="gp">...</span> <span class="go">pow(x, y, z=None, /)</span> <span class="go">...</span> <span class="gp">&gt;&gt;&gt; </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">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n">&lt;module&gt;</span> <span class="gr">TypeError</span>: <span class="n">pow() takes no keyword arguments</span> </pre></div> </div> <p><code class="docutils literal notranslate"><span class="pre">pow()</span></code> expresses that its parameters are positional-only via the <code class="docutils literal notranslate"><span class="pre">/</span></code> marker. However, this is only a documentation convention; Python developers cannot use this syntax in code.</p> <p>There are functions with other interesting semantics:</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">range()</span></code>, an overloaded function, accepts an optional parameter to the <em>left</em> of its required parameter. <a class="footnote-reference brackets" href="#range" id="id1">[4]</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">[3]</a></li> </ul> <p>One can emulate these semantics in Python code by accepting <code class="docutils literal notranslate"><span class="pre">(*args,</span> <span class="pre">**kwargs)</span></code> and parsing the arguments manually. However, this results in a disconnect between the function definition and what the function contractually accepts. The function definition does not match the logic of the argument handling.</p> <p>Additionally, the <code class="docutils literal notranslate"><span class="pre">/</span></code> syntax is used beyond CPython for specifying similar semantics (i.e., <a class="footnote-reference brackets" href="#numpy-ufuncs" id="id3">[1]</a> <a class="footnote-reference brackets" href="#scipy-gammaln" id="id4">[2]</a>); thus, indicating that these scenarios are not exclusive to CPython and the standard library.</p> </section> <section id="problems-without-positional-only-parameters"> <h3><a class="toc-backref" href="#problems-without-positional-only-parameters" role="doc-backlink">Problems Without Positional-Only Parameters</a></h3> <p>Without positional-only parameters, there are challenges for library authors and users of APIs. The following subsections outline the problems encountered by each entity.</p> <section id="challenges-for-library-authors"> <h4><a class="toc-backref" href="#challenges-for-library-authors" role="doc-backlink">Challenges for Library Authors</a></h4> <p>With positional-or-keyword parameters, the mix of calling conventions is not always desirable. Authors may want to restrict usage of an API by disallowing calling the API with keyword arguments, which exposes the name of the parameter when part of the public API. This approach is especially useful for required function parameters that already have semantic meaning (e.g, <code class="docutils literal notranslate"><span class="pre">namedtuple(typenames,</span> <span class="pre">field_names,</span> <span class="pre">…)</span></code> or when the parameter name has no true external meaning (e.g., <code class="docutils literal notranslate"><span class="pre">arg1</span></code>, <code class="docutils literal notranslate"><span class="pre">arg2</span></code>, …, etc for <code class="docutils literal notranslate"><span class="pre">min()</span></code>). If a caller of an API starts using a keyword argument, the library author cannot rename the parameter because it would be a breaking change.</p> <p>Positional-only parameters can be emulated by extracting arguments from <code class="docutils literal notranslate"><span class="pre">*args</span></code> one by one. However, this approach is error-prone and is not synonymous with the function definition, as previously mentioned. The usage of the function is ambiguous and forces users to look at <code class="docutils literal notranslate"><span class="pre">help()</span></code>, the associated auto-generated documentation, or source code to understand what parameters the function contractually accepts.</p> </section> <section id="challenges-for-users-of-an-api"> <h4><a class="toc-backref" href="#challenges-for-users-of-an-api" role="doc-backlink">Challenges for Users of an API</a></h4> <p>Users may be surprised when first encountering positional-only notation. This is expected given that it has only recently been documented <a class="footnote-reference brackets" href="#document-positional-only" id="id5">[13]</a> and it is not possible to use in Python code. For these reasons, this notation is currently an outlier that appears only in CPython APIs developed in C. Documenting the notation and making it possible to use it in Python code would eliminate this disconnect.</p> <p>Furthermore, the current documentation for positional-only parameters is inconsistent:</p> <ul class="simple"> <li>Some functions denote optional groups of positional-only parameters by enclosing them in nested square brackets. <a class="footnote-reference brackets" href="#border" id="id6">[5]</a></li> <li>Some functions denote optional groups of positional-only parameters by presenting multiple prototypes with varying numbers of parameters. <a class="footnote-reference brackets" href="#sendfile" id="id7">[6]</a></li> <li>Some functions use <em>both</em> of the above approaches. <a class="footnote-reference brackets" href="#range" id="id8">[4]</a> <a class="footnote-reference brackets" href="#addch" id="id9">[7]</a></li> </ul> <p>Another point the current documentation does not distinguish is whether a function takes positional-only parameters. <code class="docutils literal notranslate"><span class="pre">open()</span></code> accepts keyword arguments; however, <code class="docutils literal notranslate"><span class="pre">ord()</span></code> does not — there is no way of telling just by reading the existing documentation.</p> </section> </section> <section id="benefits-of-positional-only-parameters"> <h3><a class="toc-backref" href="#benefits-of-positional-only-parameters" role="doc-backlink">Benefits of Positional-Only Parameters</a></h3> <p>Positional-only parameters give more control to library authors to better express the intended usage of an API and allows the API to evolve in a safe, backward-compatible way. Additionally, it makes the Python language more consistent with existing documentation and the behavior of various “builtin” and standard library functions.</p> <section id="empowering-library-authors"> <h4><a class="toc-backref" href="#empowering-library-authors" role="doc-backlink">Empowering Library Authors</a></h4> <p>Library authors would have the flexibility to change the name of positional-only parameters without breaking callers. This flexibility reduces the cognitive burden for choosing an appropriate public-facing name for required parameters or parameters that have no true external semantic meaning.</p> <p>Positional-only parameters are useful in several situations such as:</p> <ul class="simple"> <li>when a function accepts any keyword argument but also can accept a positional one</li> <li>when a parameter has no external semantic meaning</li> <li>when an API’s parameters are required and unambiguous</li> </ul> <p>A key scenario is when a function accepts any keyword argument but can also accepts a positional one. Prominent examples are <code class="docutils literal notranslate"><span class="pre">Formatter.format</span></code> and <code class="docutils literal notranslate"><span class="pre">dict.update</span></code>. For instance, <code class="docutils literal notranslate"><span class="pre">dict.update</span></code> accepts a dictionary (positionally), an iterable of key/value pairs (positionally), or multiple keyword arguments. In this scenario, if the dictionary parameter were not positional-only, the user could not use the name that the function definition uses for the parameter or, conversely, the function could not distinguish easily if the argument received is the dictionary/iterable or a keyword argument for updating the key/value pair.</p> <p>Another scenario where positional-only parameters are useful is when the parameter name has no true external semantic meaning. For example, let’s say we want to create a function that converts from one type to another:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">as_my_type</span><span class="p">(</span><span class="n">x</span><span class="p">):</span> <span class="o">...</span> </pre></div> </div> <p>The name of the parameter provides no intrinsic value and forces the API author to maintain its name forever since callers might pass <code class="docutils literal notranslate"><span class="pre">x</span></code> as a keyword argument.</p> <p>Additionally, positional-only parameters are useful when an API’s parameters are required and is unambiguous with respect to function. For example:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">add_to_queue</span><span class="p">(</span><span class="n">item</span><span class="p">:</span> <span class="n">QueueItem</span><span class="p">):</span> <span class="o">...</span> </pre></div> </div> <p>The name of the function makes clear the argument expected. A keyword argument provides minimal benefit and also limits the future evolution of the API. Say at a later time we want this function to be able to take multiple items, while preserving backwards compatibility:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">add_to_queue</span><span class="p">(</span><span class="n">items</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="n">QueueItem</span><span class="p">,</span> <span class="n">List</span><span class="p">[</span><span class="n">QueueItem</span><span class="p">]]):</span> <span class="o">...</span> </pre></div> </div> <p>or to take them by using argument lists:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">add_to_queue</span><span class="p">(</span><span class="o">*</span><span class="n">items</span><span class="p">:</span> <span class="n">QueueItem</span><span class="p">):</span> <span class="o">...</span> </pre></div> </div> <p>the author would be forced to always keep the original parameter name to avoid potentially breaking callers.</p> <p>By being able to specify positional-only parameters, an author can change the name of the parameters freely or even change them to <code class="docutils literal notranslate"><span class="pre">*args</span></code>, as seen in the previous example. There are multiple function definitions in the standard library which fall into this category. For example, the required parameter to <code class="docutils literal notranslate"><span class="pre">collections.defaultdict</span></code> (called <em>default_factory</em> in its documentation) can only be passed positionally. One special case of this situation is the <em>self</em> parameter for class methods: it is undesirable that a caller can bind by keyword to the name <code class="docutils literal notranslate"><span class="pre">self</span></code> when calling the method from the class:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">io</span><span class="o">.</span><span class="n">FileIO</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="bp">self</span><span class="o">=</span><span class="n">f</span><span class="p">,</span> <span class="n">b</span><span class="o">=</span><span class="sa">b</span><span class="s2">&quot;data&quot;</span><span class="p">)</span> </pre></div> </div> <p>Indeed, function definitions from the standard library implemented in C usually take <code class="docutils literal notranslate"><span class="pre">self</span></code> as a positional-only parameter:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">help</span><span class="p">(</span><span class="n">io</span><span class="o">.</span><span class="n">FileIO</span><span class="o">.</span><span class="n">write</span><span class="p">)</span> <span class="go">Help on method_descriptor:</span> <span class="go">write(self, b, /)</span> <span class="go"> Write buffer b to file, return number of bytes written.</span> </pre></div> </div> </section> <section id="improving-language-consistency"> <h4><a class="toc-backref" href="#improving-language-consistency" role="doc-backlink">Improving Language Consistency</a></h4> <p>The Python language would be more consistent with positional-only parameters. If the concept is a normal feature of Python rather than a feature exclusive to extension modules, it would reduce confusion for users encountering functions with positional-only parameters. Some major third-party packages are already using the <code class="docutils literal notranslate"><span class="pre">/</span></code> notation in their function definitions <a class="footnote-reference brackets" href="#numpy-ufuncs" id="id10">[1]</a> <a class="footnote-reference brackets" href="#scipy-gammaln" id="id11">[2]</a>.</p> <p>Bridging the gap found between “builtin” functions which specify positional-only parameters and pure Python implementations that lack the positional syntax would improve consistency. The <code class="docutils literal notranslate"><span class="pre">/</span></code> syntax is already exposed in the existing documentation such as when builtins and interfaces are generated by the argument clinic.</p> <p>Another essential aspect to consider is <a class="pep reference internal" href="../pep-0399/" title="PEP 399 – Pure Python/C Accelerator Module Compatibility Requirements">PEP 399</a>, which mandates that pure Python versions of modules in the standard library <em>must</em> have the same interface and semantics that the accelerator modules implemented in C. For example, if <code class="docutils literal notranslate"><span class="pre">collections.defaultdict</span></code> were to have a pure Python implementation it would need to make use of positional-only parameters to match the interface of its C counterpart.</p> </section> </section> </section> <section id="rationale"> <h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2> <p>We propose to introduce positional-only parameters as a new syntax to the Python language.</p> <p>The new syntax will enable library authors to further control how their API can be called. It will allow designating which parameters must be called as positional-only, while preventing them from being called as keyword arguments.</p> <p>Previously, (informational) <a class="pep reference internal" href="../pep-0457/" title="PEP 457 – Notation For Positional-Only Parameters">PEP 457</a> defined the syntax, but with a much more vague scope. This PEP takes the original proposal a step further by justifying the syntax and providing an implementation for the <code class="docutils literal notranslate"><span class="pre">/</span></code> syntax in function definitions.</p> <section id="performance"> <h3><a class="toc-backref" href="#performance" role="doc-backlink">Performance</a></h3> <p>In addition to the aforementioned benefits, the parsing and handling of positional-only arguments is faster. This performance benefit can be demonstrated in this thread about converting keyword arguments to positional: <a class="footnote-reference brackets" href="#thread-keyword-to-positional" id="id12">[11]</a>. Due to this speedup, there has been a recent trend towards moving builtins away from keyword arguments: recently, backwards-incompatible changes were made to disallow keyword arguments to <code class="docutils literal notranslate"><span class="pre">bool</span></code>, <code class="docutils literal notranslate"><span class="pre">float</span></code>, <code class="docutils literal notranslate"><span class="pre">list</span></code>, <code class="docutils literal notranslate"><span class="pre">int</span></code>, <code class="docutils literal notranslate"><span class="pre">tuple</span></code>.</p> </section> <section id="maintainability"> <h3><a class="toc-backref" href="#maintainability" role="doc-backlink">Maintainability</a></h3> <p>Providing a way to specify positional-only parameters in Python will make it easier to maintain pure Python implementations of C modules. Additionally, library authors defining functions will have the choice for choosing positional-only parameters if they determine that passing a keyword argument provides no additional clarity.</p> <p>This is a well discussed, recurring topic on the Python mailing lists:</p> <ul class="simple"> <li>September 2018: <a class="reference external" href="https://mail.python.org/pipermail/python-ideas/2018-September/053233.html">Anders Hovmöller: [Python-ideas] Positional-only parameters</a></li> <li>February 2017: <a class="reference external" href="https://mail.python.org/pipermail/python-ideas/2017-February/044879.html">Victor Stinner: [Python-ideas] Positional-only parameters</a>, <a class="reference external" href="https://mail.python.org/pipermail/python-ideas/2017-March/044956.html">discussion continued in March</a></li> <li>February 2017: <a class="footnote-reference brackets" href="#python-ideas-decorator-based" id="id13">[9]</a></li> <li>March 2012: <a class="footnote-reference brackets" href="#guido" id="id14">[8]</a></li> <li>May 2007: <a class="reference external" href="https://mail.python.org/pipermail/python-ideas/2007-May/000704.html">George Sakkis: [Python-ideas] Positional only arguments</a></li> <li>May 2006: <a class="reference external" href="https://mail.python.org/pipermail/python-dev/2006-May/064790.html">Benji York: [Python-Dev] Positional-only Arguments</a></li> </ul> </section> <section id="logical-ordering"> <h3><a class="toc-backref" href="#logical-ordering" role="doc-backlink">Logical ordering</a></h3> <p>Positional-only parameters also have the (minor) benefit of enforcing some logical order when calling interfaces that make use of them. For example, the <code class="docutils literal notranslate"><span class="pre">range</span></code> function takes all its parameters positionally and disallows forms like:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nb">range</span><span class="p">(</span><span class="n">stop</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">start</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">step</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span> <span class="nb">range</span><span class="p">(</span><span class="n">stop</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">step</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">start</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span> <span class="nb">range</span><span class="p">(</span><span class="n">step</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">start</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">stop</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span> <span class="nb">range</span><span class="p">(</span><span class="n">step</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">stop</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">start</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span> </pre></div> </div> <p>at the price of disallowing the use of keyword arguments for the (unique) intended order:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nb">range</span><span class="p">(</span><span class="n">start</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">stop</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">step</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span> </pre></div> </div> </section> <section id="compatibility-for-pure-python-and-c-modules"> <h3><a class="toc-backref" href="#compatibility-for-pure-python-and-c-modules" role="doc-backlink">Compatibility for Pure Python and C Modules</a></h3> <p>Another critical motivation for positional-only parameters is <a class="pep reference internal" href="../pep-0399/" title="PEP 399 – Pure Python/C Accelerator Module Compatibility Requirements">PEP 399</a>: Pure Python/C Accelerator Module Compatibility Requirements. This PEP states that:</p> <blockquote> <div>This PEP requires that in these instances that the C code must pass the test suite used for the pure Python code to act as much as a drop-in replacement as reasonably possible</div></blockquote> <p>If the C code is implemented using the existing capabilities to implement positional-only parameters using the argument clinic, and related machinery, it is not possible for the pure Python counterpart to match the provided interface and requirements. This creates a disparity between the interfaces of some functions and classes in the CPython standard library and other Python implementations. For example:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span>$ python3 # CPython 3.7.2 &gt;&gt;&gt; import binascii; binascii.crc32(data=b&#39;data&#39;) TypeError: crc32() takes no keyword arguments $ pypy3 # PyPy 6.0.0 &gt;&gt;&gt;&gt; import binascii; binascii.crc32(data=b&#39;data&#39;) 2918445923 </pre></div> </div> <p>Other Python implementations can reproduce the CPython APIs manually, but this goes against the spirit of <a class="pep reference internal" href="../pep-0399/" title="PEP 399 – Pure Python/C Accelerator Module Compatibility Requirements">PEP 399</a> to avoid duplication of effort by mandating that all modules added to Python’s standard library <strong>must</strong> have a pure Python implementation with the same interface and semantics.</p> </section> <section id="consistency-in-subclasses"> <h3><a class="toc-backref" href="#consistency-in-subclasses" role="doc-backlink">Consistency in Subclasses</a></h3> <p>Another scenario where positional-only parameters provide benefit occurs when a subclass overrides a method of the base class and changes the name of parameters that are intended to be positional:</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="k">def</span> <span class="nf">meth</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">arg</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span> <span class="o">...</span> <span class="k">class</span> <span class="nc">Sub</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span> <span class="k">def</span> <span class="nf">meth</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other_arg</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span> <span class="o">...</span> <span class="k">def</span> <span class="nf">func</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="n">Base</span><span class="p">):</span> <span class="n">x</span><span class="o">.</span><span class="n">meth</span><span class="p">(</span><span class="n">arg</span><span class="o">=</span><span class="mi">12</span><span class="p">)</span> <span class="n">func</span><span class="p">(</span><span class="n">Sub</span><span class="p">())</span> <span class="c1"># Runtime error</span> </pre></div> </div> <p>This situation could be considered a Liskov violation — the subclass cannot be used in a context when an instance of the base class is expected. Renaming arguments when overloading methods can happen when the subclass has reasons to use a different choice for the parameter name that is more appropriate for the specific domain of the subclass (e.g., when subclassing <code class="docutils literal notranslate"><span class="pre">Mapping</span></code> to implement a DNS lookup cache, the derived class may not want to use the generic argument names ‘key’ and ‘value’ but rather ‘host’ and ‘address’). Having this function definition with positional-only parameters can avoid this problem because users will not be able to call the interface using keyword arguments. In general, designing for subclassing usually involves anticipating code that hasn’t been written yet and over which the author has no control. Having measures that can facilitate the evolution of interfaces in a backwards-compatible would be useful for library authors.</p> </section> <section id="optimizations"> <h3><a class="toc-backref" href="#optimizations" role="doc-backlink">Optimizations</a></h3> <p>A final argument in favor of positional-only parameters is that they allow some new optimizations like the ones already present in the argument clinic due to the fact that parameters are expected to be passed in strict order. For example, CPython’s internal <code class="docutils literal notranslate"><span class="pre">METH_FASTCALL</span></code> calling convention has been recently specialized for functions with positional-only parameters to eliminate the cost for handling empty keywords. Similar performance improvements can be applied when creating the evaluation frame of Python functions thanks to positional-only parameters.</p> </section> </section> <section id="specification"> <h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2> <section id="syntax-and-semantics"> <h3><a class="toc-backref" href="#syntax-and-semantics" role="doc-backlink">Syntax and Semantics</a></h3> <p>From the “ten-thousand foot view”, eliding <code class="docutils literal notranslate"><span class="pre">*args</span></code> and <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> for illustration, the grammar for a function definition would look like:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</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 example, the new syntax for function definitions would look like:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</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>The following would apply:</p> <ul class="simple"> <li>All parameters left of the <code class="docutils literal notranslate"><span class="pre">/</span></code> are treated as positional-only.</li> <li>If <code class="docutils literal notranslate"><span class="pre">/</span></code> is not specified in the function definition, that function does not accept any positional-only arguments.</li> <li>The logic around optional values for positional-only parameters remains the same as for positional-or-keyword parameters.</li> <li>Once a positional-only parameter is specified with a default, the following positional-only and positional-or-keyword parameters need to have defaults as well.</li> <li>Positional-only parameters which do not have default values are <em>required</em> positional-only parameters.</li> </ul> <p>Therefore, the following would be valid function definitions:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">name</span><span class="p">(</span><span class="n">p1</span><span class="p">,</span> <span class="n">p2</span><span class="p">,</span> <span class="o">/</span><span class="p">,</span> <span class="n">p_or_kw</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">kw</span><span class="p">):</span> <span class="k">def</span> <span class="nf">name</span><span class="p">(</span><span class="n">p1</span><span class="p">,</span> <span class="n">p2</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">/</span><span class="p">,</span> <span class="n">p_or_kw</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">kw</span><span class="p">):</span> <span class="k">def</span> <span class="nf">name</span><span class="p">(</span><span class="n">p1</span><span class="p">,</span> <span class="n">p2</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">/</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">kw</span><span class="p">):</span> <span class="k">def</span> <span class="nf">name</span><span class="p">(</span><span class="n">p1</span><span class="p">,</span> <span class="n">p2</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">/</span><span class="p">):</span> <span class="k">def</span> <span class="nf">name</span><span class="p">(</span><span class="n">p1</span><span class="p">,</span> <span class="n">p2</span><span class="p">,</span> <span class="o">/</span><span class="p">,</span> <span class="n">p_or_kw</span><span class="p">):</span> <span class="k">def</span> <span class="nf">name</span><span class="p">(</span><span class="n">p1</span><span class="p">,</span> <span class="n">p2</span><span class="p">,</span> <span class="o">/</span><span class="p">):</span> </pre></div> </div> <p>Just like today, the following would be valid function definitions:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">name</span><span class="p">(</span><span class="n">p_or_kw</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">kw</span><span class="p">):</span> <span class="k">def</span> <span class="nf">name</span><span class="p">(</span><span class="o">*</span><span class="p">,</span> <span class="n">kw</span><span class="p">):</span> </pre></div> </div> <p>While the following would be invalid:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">name</span><span class="p">(</span><span class="n">p1</span><span class="p">,</span> <span class="n">p2</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">/</span><span class="p">,</span> <span class="n">p_or_kw</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">kw</span><span class="p">):</span> <span class="k">def</span> <span class="nf">name</span><span class="p">(</span><span class="n">p1</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">p2</span><span class="p">,</span> <span class="o">/</span><span class="p">,</span> <span class="n">p_or_kw</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">kw</span><span class="p">):</span> <span class="k">def</span> <span class="nf">name</span><span class="p">(</span><span class="n">p1</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">p2</span><span class="p">,</span> <span class="o">/</span><span class="p">):</span> </pre></div> </div> </section> <section id="full-grammar-specification"> <h3><a class="toc-backref" href="#full-grammar-specification" role="doc-backlink">Full Grammar Specification</a></h3> <p>A simplified view of the proposed grammar specification is:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">typedargslist</span><span class="p">:</span> <span class="n">tfpdef</span> <span class="p">[</span><span class="s1">&#39;=&#39;</span> <span class="n">test</span><span class="p">]</span> <span class="p">(</span><span class="s1">&#39;,&#39;</span> <span class="n">tfpdef</span> <span class="p">[</span><span class="s1">&#39;=&#39;</span> <span class="n">test</span><span class="p">])</span><span class="o">*</span> <span class="s1">&#39;,&#39;</span> <span class="s1">&#39;/&#39;</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span> <span class="c1"># and so on</span> <span class="n">varargslist</span><span class="p">:</span> <span class="n">vfpdef</span> <span class="p">[</span><span class="s1">&#39;=&#39;</span> <span class="n">test</span><span class="p">]</span> <span class="p">(</span><span class="s1">&#39;,&#39;</span> <span class="n">vfpdef</span> <span class="p">[</span><span class="s1">&#39;=&#39;</span> <span class="n">test</span><span class="p">])</span><span class="o">*</span> <span class="s1">&#39;,&#39;</span> <span class="s1">&#39;/&#39;</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span> <span class="c1"># and so on</span> </pre></div> </div> <p>Based on the reference implementation in this PEP, the new rule for <code class="docutils literal notranslate"><span class="pre">typedarglist</span></code> would be:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">typedargslist</span><span class="p">:</span> <span class="p">(</span><span class="n">tfpdef</span> <span class="p">[</span><span class="s1">&#39;=&#39;</span> <span class="n">test</span><span class="p">]</span> <span class="p">(</span><span class="s1">&#39;,&#39;</span> <span class="n">tfpdef</span> <span class="p">[</span><span class="s1">&#39;=&#39;</span> <span class="n">test</span><span class="p">])</span><span class="o">*</span> <span class="s1">&#39;,&#39;</span> <span class="s1">&#39;/&#39;</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span> <span class="p">[</span><span class="n">tfpdef</span> <span class="p">[</span><span class="s1">&#39;=&#39;</span> <span class="n">test</span><span class="p">]</span> <span class="p">(</span><span class="s1">&#39;,&#39;</span> <span class="n">tfpdef</span> <span class="p">[</span><span class="s1">&#39;=&#39;</span> <span class="n">test</span><span class="p">])</span><span class="o">*</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span> <span class="p">[</span> <span class="s1">&#39;*&#39;</span> <span class="p">[</span><span class="n">tfpdef</span><span class="p">]</span> <span class="p">(</span><span class="s1">&#39;,&#39;</span> <span class="n">tfpdef</span> <span class="p">[</span><span class="s1">&#39;=&#39;</span> <span class="n">test</span><span class="p">])</span><span class="o">*</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span> <span class="p">[</span><span class="s1">&#39;**&#39;</span> <span class="n">tfpdef</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span><span class="p">]]]</span> <span class="o">|</span> <span class="s1">&#39;**&#39;</span> <span class="n">tfpdef</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span><span class="p">]]]</span> <span class="o">|</span> <span class="s1">&#39;*&#39;</span> <span class="p">[</span><span class="n">tfpdef</span><span class="p">]</span> <span class="p">(</span><span class="s1">&#39;,&#39;</span> <span class="n">tfpdef</span> <span class="p">[</span><span class="s1">&#39;=&#39;</span> <span class="n">test</span><span class="p">])</span><span class="o">*</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span> <span class="p">[</span><span class="s1">&#39;**&#39;</span> <span class="n">tfpdef</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span><span class="p">]]]</span> <span class="o">|</span> <span class="s1">&#39;**&#39;</span> <span class="n">tfpdef</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span><span class="p">]]</span> <span class="p">]</span> <span class="p">)</span><span class="o">|</span> <span class="p">(</span> <span class="n">tfpdef</span> <span class="p">[</span><span class="s1">&#39;=&#39;</span> <span class="n">test</span><span class="p">]</span> <span class="p">(</span><span class="s1">&#39;,&#39;</span> <span class="n">tfpdef</span> <span class="p">[</span><span class="s1">&#39;=&#39;</span> <span class="n">test</span><span class="p">])</span><span class="o">*</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span> <span class="p">[</span> <span class="s1">&#39;*&#39;</span> <span class="p">[</span><span class="n">tfpdef</span><span class="p">]</span> <span class="p">(</span><span class="s1">&#39;,&#39;</span> <span class="n">tfpdef</span> <span class="p">[</span><span class="s1">&#39;=&#39;</span> <span class="n">test</span><span class="p">])</span><span class="o">*</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span> <span class="p">[</span><span class="s1">&#39;**&#39;</span> <span class="n">tfpdef</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span><span class="p">]]]</span> <span class="o">|</span> <span class="s1">&#39;**&#39;</span> <span class="n">tfpdef</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span><span class="p">]]]</span> <span class="o">|</span> <span class="s1">&#39;*&#39;</span> <span class="p">[</span><span class="n">tfpdef</span><span class="p">]</span> <span class="p">(</span><span class="s1">&#39;,&#39;</span> <span class="n">tfpdef</span> <span class="p">[</span><span class="s1">&#39;=&#39;</span> <span class="n">test</span><span class="p">])</span><span class="o">*</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span> <span class="p">[</span><span class="s1">&#39;**&#39;</span> <span class="n">tfpdef</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span><span class="p">]]]</span> <span class="o">|</span> <span class="s1">&#39;**&#39;</span> <span class="n">tfpdef</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span><span class="p">])</span> </pre></div> </div> <p>and for <code class="docutils literal notranslate"><span class="pre">varargslist</span></code> would be:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">varargslist</span><span class="p">:</span> <span class="n">vfpdef</span> <span class="p">[</span><span class="s1">&#39;=&#39;</span> <span class="n">test</span> <span class="p">](</span><span class="s1">&#39;,&#39;</span> <span class="n">vfpdef</span> <span class="p">[</span><span class="s1">&#39;=&#39;</span> <span class="n">test</span><span class="p">])</span><span class="o">*</span> <span class="s1">&#39;,&#39;</span> <span class="s1">&#39;/&#39;</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span> <span class="p">[</span> <span class="p">(</span><span class="n">vfpdef</span> <span class="p">[</span><span class="s1">&#39;=&#39;</span> <span class="n">test</span><span class="p">]</span> <span class="p">(</span><span class="s1">&#39;,&#39;</span> <span class="n">vfpdef</span> <span class="p">[</span><span class="s1">&#39;=&#39;</span> <span class="n">test</span><span class="p">])</span><span class="o">*</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span> <span class="p">[</span> <span class="s1">&#39;*&#39;</span> <span class="p">[</span><span class="n">vfpdef</span><span class="p">]</span> <span class="p">(</span><span class="s1">&#39;,&#39;</span> <span class="n">vfpdef</span> <span class="p">[</span><span class="s1">&#39;=&#39;</span> <span class="n">test</span><span class="p">])</span><span class="o">*</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span> <span class="p">[</span><span class="s1">&#39;**&#39;</span> <span class="n">vfpdef</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span><span class="p">]]]</span> <span class="o">|</span> <span class="s1">&#39;**&#39;</span> <span class="n">vfpdef</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span><span class="p">]]]</span> <span class="o">|</span> <span class="s1">&#39;*&#39;</span> <span class="p">[</span><span class="n">vfpdef</span><span class="p">]</span> <span class="p">(</span><span class="s1">&#39;,&#39;</span> <span class="n">vfpdef</span> <span class="p">[</span><span class="s1">&#39;=&#39;</span> <span class="n">test</span><span class="p">])</span><span class="o">*</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span> <span class="p">[</span><span class="s1">&#39;**&#39;</span> <span class="n">vfpdef</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span><span class="p">]]]</span> <span class="o">|</span> <span class="s1">&#39;**&#39;</span> <span class="n">vfpdef</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span><span class="p">])</span> <span class="p">]]</span> <span class="o">|</span> <span class="p">(</span><span class="n">vfpdef</span> <span class="p">[</span><span class="s1">&#39;=&#39;</span> <span class="n">test</span><span class="p">]</span> <span class="p">(</span><span class="s1">&#39;,&#39;</span> <span class="n">vfpdef</span> <span class="p">[</span><span class="s1">&#39;=&#39;</span> <span class="n">test</span><span class="p">])</span><span class="o">*</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span> <span class="p">[</span> <span class="s1">&#39;*&#39;</span> <span class="p">[</span><span class="n">vfpdef</span><span class="p">]</span> <span class="p">(</span><span class="s1">&#39;,&#39;</span> <span class="n">vfpdef</span> <span class="p">[</span><span class="s1">&#39;=&#39;</span> <span class="n">test</span><span class="p">])</span><span class="o">*</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span> <span class="p">[</span><span class="s1">&#39;**&#39;</span> <span class="n">vfpdef</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span><span class="p">]]]</span> <span class="o">|</span> <span class="s1">&#39;**&#39;</span> <span class="n">vfpdef</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span><span class="p">]]]</span> <span class="o">|</span> <span class="s1">&#39;*&#39;</span> <span class="p">[</span><span class="n">vfpdef</span><span class="p">]</span> <span class="p">(</span><span class="s1">&#39;,&#39;</span> <span class="n">vfpdef</span> <span class="p">[</span><span class="s1">&#39;=&#39;</span> <span class="n">test</span><span class="p">])</span><span class="o">*</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span> <span class="p">[</span><span class="s1">&#39;**&#39;</span> <span class="n">vfpdef</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span><span class="p">]]]</span> <span class="o">|</span> <span class="s1">&#39;**&#39;</span> <span class="n">vfpdef</span> <span class="p">[</span><span class="s1">&#39;,&#39;</span><span class="p">]</span> <span class="p">)</span> </pre></div> </div> </section> <section id="semantic-corner-case"> <h3><a class="toc-backref" href="#semantic-corner-case" role="doc-backlink">Semantic Corner Case</a></h3> <p>The following is an interesting corollary of the specification. Consider this function definition:</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">name</span><span class="p">,</span> <span class="o">**</span><span class="n">kwds</span><span class="p">):</span> <span class="k">return</span> <span class="s1">&#39;name&#39;</span> <span class="ow">in</span> <span class="n">kwds</span> </pre></div> </div> <p>There is no possible call that will make it return <code class="docutils literal notranslate"><span class="pre">True</span></code>. For example:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">foo</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="o">**</span><span class="p">{</span><span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="mi">2</span><span class="p">})</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">TypeError</span>: <span class="n">foo() got multiple values for argument &#39;name&#39;</span> <span class="gp">&gt;&gt;&gt;</span> </pre></div> </div> <p>But using <code class="docutils literal notranslate"><span class="pre">/</span></code> we can support this:</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">name</span><span class="p">,</span> <span class="o">/</span><span class="p">,</span> <span class="o">**</span><span class="n">kwds</span><span class="p">):</span> <span class="k">return</span> <span class="s1">&#39;name&#39;</span> <span class="ow">in</span> <span class="n">kwds</span> </pre></div> </div> <p>Now the above call will return <code class="docutils literal notranslate"><span class="pre">True</span></code>.</p> <p>In other words, the names of positional-only parameters can be used in <code class="docutils literal notranslate"><span class="pre">**kwds</span></code> without ambiguity. (As another example, this benefits the signatures of <code class="docutils literal notranslate"><span class="pre">dict()</span></code> and <code class="docutils literal notranslate"><span class="pre">dict.update()</span></code>.)</p> </section> <section id="origin-of-as-a-separator"> <h3><a class="toc-backref" href="#origin-of-as-a-separator" role="doc-backlink">Origin of “/” as a Separator</a></h3> <p>Using <code class="docutils literal notranslate"><span class="pre">/</span></code> as a separator was initially proposed by Guido van Rossum in 2012 <a class="footnote-reference brackets" href="#guido" id="id15">[8]</a> :</p> <blockquote> <div>Alternative proposal: how about using ‘/’ ? It’s kind of the opposite of ‘*’ which means “keyword argument”, and ‘/’ is not a new character.</div></blockquote> </section> </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>Introducing a dedicated syntax to mark positional-only parameters is closely analogous to existing keyword-only arguments. Teaching these concepts together may <em>simplify</em> how to teach the possible function definitions a user may encounter or design.</p> <p>This PEP recommends adding a new subsection to the Python documentation, in the section <a class="reference external" href="https://docs.python.org/3.7/tutorial/controlflow.html#more-on-defining-functions">“More on Defining Functions”</a>, where the rest of the argument types are discussed. The following paragraphs serve as a draft for these additions. They will introduce the notation for both positional-only and keyword-only parameters. It is not intended to be exhaustive, nor should it be considered the final version to be incorporated into the documentation.</p> <hr class="docutils" /> <p>By default, arguments may be passed to a Python function either by position or explicitly by keyword. For readability and performance, it makes sense to restrict the way arguments can be passed so that a developer need only look at the function definition to determine if items are passed by position, by position or keyword, or by keyword.</p> <p>A function definition may look like:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="n">pos1</span><span class="p">,</span> <span class="n">pos2</span><span class="p">,</span> <span class="o">/</span><span class="p">,</span> <span class="n">pos_or_kwd</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">kwd1</span><span class="p">,</span> <span class="n">kwd2</span><span class="p">):</span> <span class="o">-----------</span> <span class="o">----------</span> <span class="o">----------</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="n">Positional</span> <span class="ow">or</span> <span class="n">keyword</span> <span class="o">|</span> <span class="o">|</span> <span class="o">-</span> <span class="n">Keyword</span> <span class="n">only</span> <span class="o">--</span> <span class="n">Positional</span> <span class="n">only</span> </pre></div> </div> <p>where <code class="docutils literal notranslate"><span class="pre">/</span></code> and <code class="docutils literal notranslate"><span class="pre">*</span></code> are optional. If used, these symbols indicate the kind of parameter by how the arguments may be passed to the function: positional-only, positional-or-keyword, and keyword-only. Keyword parameters are also referred to as named parameters.</p> <section id="positional-or-keyword-arguments"> <h3><a class="toc-backref" href="#positional-or-keyword-arguments" role="doc-backlink">Positional-or-Keyword Arguments</a></h3> <p>If <code class="docutils literal notranslate"><span class="pre">/</span></code> and <code class="docutils literal notranslate"><span class="pre">*</span></code> are not present in the function definition, arguments may be passed to a function by position or by keyword.</p> </section> <section id="positional-only-parameters"> <h3><a class="toc-backref" href="#positional-only-parameters" role="doc-backlink">Positional-Only Parameters</a></h3> <p>Looking at this in a bit more detail, it is possible to mark certain parameters as <em>positional-only</em>. If <em>positional-only</em>, the parameters’ order matters, and the parameters cannot be passed by keyword. Positional-only parameters would be placed before a <code class="docutils literal notranslate"><span class="pre">/</span></code> (forward-slash). The <code class="docutils literal notranslate"><span class="pre">/</span></code> is used to logically separate the positional-only parameters from the rest of the parameters. If there is no <code class="docutils literal notranslate"><span class="pre">/</span></code> in the function definition, there are no positional-only parameters.</p> <p>Parameters following the <code class="docutils literal notranslate"><span class="pre">/</span></code> may be <em>positional-or-keyword</em> or <em>keyword-only</em>.</p> </section> <section id="keyword-only-arguments"> <h3><a class="toc-backref" href="#keyword-only-arguments" role="doc-backlink">Keyword-Only Arguments</a></h3> <p>To mark parameters as <em>keyword-only</em>, indicating the parameters must be passed by keyword argument, place an <code class="docutils literal notranslate"><span class="pre">*</span></code> in the arguments list just before the first <em>keyword-only</em> parameter.</p> </section> <section id="function-examples"> <h3><a class="toc-backref" href="#function-examples" role="doc-backlink">Function Examples</a></h3> <p>Consider the following example function definitions paying close attention to the markers <code class="docutils literal notranslate"><span class="pre">/</span></code> and <code class="docutils literal notranslate"><span class="pre">*</span></code>:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="k">def</span> <span class="nf">standard_arg</span><span class="p">(</span><span class="n">arg</span><span class="p">):</span> <span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="n">arg</span><span class="p">)</span> <span class="gp">...</span> <span class="gp">&gt;&gt;&gt; </span><span class="k">def</span> <span class="nf">pos_only_arg</span><span class="p">(</span><span class="n">arg</span><span class="p">,</span> <span class="o">/</span><span class="p">):</span> <span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="n">arg</span><span class="p">)</span> <span class="gp">...</span> <span class="gp">&gt;&gt;&gt; </span><span class="k">def</span> <span class="nf">kwd_only_arg</span><span class="p">(</span><span class="o">*</span><span class="p">,</span> <span class="n">arg</span><span class="p">):</span> <span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="n">arg</span><span class="p">)</span> <span class="gp">...</span> <span class="gp">&gt;&gt;&gt; </span><span class="k">def</span> <span class="nf">combined_example</span><span class="p">(</span><span class="n">pos_only</span><span class="p">,</span> <span class="o">/</span><span class="p">,</span> <span class="n">standard</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">kwd_only</span><span class="p">):</span> <span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="n">pos_only</span><span class="p">,</span> <span class="n">standard</span><span class="p">,</span> <span class="n">kwd_only</span><span class="p">)</span> </pre></div> </div> <p>The first function definition <code class="docutils literal notranslate"><span class="pre">standard_arg</span></code>, the most familiar form, places no restrictions on the calling convention and arguments may be passed by position or keyword:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">standard_arg</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="go">2</span> <span class="gp">&gt;&gt;&gt; </span><span class="n">standard_arg</span><span class="p">(</span><span class="n">arg</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span> <span class="go">2</span> </pre></div> </div> <p>The second function <code class="docutils literal notranslate"><span class="pre">pos_only_arg</span></code> is restricted to only use positional parameters as there is a <code class="docutils literal notranslate"><span class="pre">/</span></code> in the function definition:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">pos_only_arg</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="go">1</span> <span class="gp">&gt;&gt;&gt; </span><span class="n">pos_only_arg</span><span class="p">(</span><span class="n">arg</span><span class="o">=</span><span class="mi">1</span><span class="p">)</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">TypeError</span>: <span class="n">pos_only_arg() got an unexpected keyword argument &#39;arg&#39;</span> </pre></div> </div> <p>The third function <code class="docutils literal notranslate"><span class="pre">kwd_only_args</span></code> only allows keyword arguments as indicated by a <code class="docutils literal notranslate"><span class="pre">*</span></code> in the function definition:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">kwd_only_arg</span><span class="p">(</span><span class="mi">3</span><span class="p">)</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">TypeError</span>: <span class="n">kwd_only_arg() takes 0 positional arguments but 1 was given</span> <span class="gp">&gt;&gt;&gt; </span><span class="n">kwd_only_arg</span><span class="p">(</span><span class="n">arg</span><span class="o">=</span><span class="mi">3</span><span class="p">)</span> <span class="go">3</span> </pre></div> </div> <p>And the last uses all three calling conventions in the same function definition:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="n">combined_example</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</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">TypeError</span>: <span class="n">combined_example() takes 2 positional arguments but 3 were given</span> <span class="gp">&gt;&gt;&gt; </span><span class="n">combined_example</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="n">kwd_only</span><span class="o">=</span><span class="mi">3</span><span class="p">)</span> <span class="go">1 2 3</span> <span class="gp">&gt;&gt;&gt; </span><span class="n">combined_example</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">standard</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">kwd_only</span><span class="o">=</span><span class="mi">3</span><span class="p">)</span> <span class="go">1 2 3</span> <span class="gp">&gt;&gt;&gt; </span><span class="n">combined_example</span><span class="p">(</span><span class="n">pos_only</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">standard</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">kwd_only</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">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n">&lt;module&gt;</span> <span class="gr">TypeError</span>: <span class="n">combined_example() got an unexpected keyword argument &#39;pos_only&#39;</span> </pre></div> </div> </section> <section id="recap"> <h3><a class="toc-backref" href="#recap" role="doc-backlink">Recap</a></h3> <p>The use case will determine which parameters to use in the function definition:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="n">pos1</span><span class="p">,</span> <span class="n">pos2</span><span class="p">,</span> <span class="o">/</span><span class="p">,</span> <span class="n">pos_or_kwd</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">kwd1</span><span class="p">,</span> <span class="n">kwd2</span><span class="p">):</span> </pre></div> </div> <p>As guidance:</p> <ul class="simple"> <li>Use positional-only if names do not matter or have no meaning, and there are only a few arguments which will always be passed in the same order.</li> <li>Use keyword-only when names have meaning and the function definition is more understandable by being explicit with names.</li> </ul> </section> </section> <section id="reference-implementation"> <h2><a class="toc-backref" href="#reference-implementation" role="doc-backlink">Reference Implementation</a></h2> <p>An initial implementation that passes the CPython test suite is available for evaluation <a class="footnote-reference brackets" href="#posonly-impl" id="id16">[10]</a>.</p> <p>The benefits of this implementations are speed of handling positional-only parameters, consistency with the implementation of keyword-only parameters (PEP 3102), and a simpler implementation of all the tools and modules that would be impacted by this change.</p> </section> <section id="rejected-ideas"> <h2><a class="toc-backref" href="#rejected-ideas" role="doc-backlink">Rejected Ideas</a></h2> <section id="do-nothing"> <h3><a class="toc-backref" href="#do-nothing" role="doc-backlink">Do Nothing</a></h3> <p>Always an option — the status quo. While this was considered, the aforementioned benefits are worth the addition to the language.</p> </section> <section id="decorators"> <h3><a class="toc-backref" href="#decorators" role="doc-backlink">Decorators</a></h3> <p>It has been suggested on python-ideas <a class="footnote-reference brackets" href="#python-ideas-decorator-based" id="id17">[9]</a> to provide a decorator written in Python for this feature.</p> <p>This approach has the benefit of not polluting function definition with additional syntax. However, we have decided to reject this idea because:</p> <ul class="simple"> <li>It introduces an asymmetry with how parameter behavior is declared.</li> <li>It makes it difficult for static analyzers and type checkers to safely identify positional-only parameters. They would need to query the AST for the list of decorators and identify the correct one by name or with extra heuristics, while keyword-only parameters are exposed directly in the AST. In order for tools to correctly identify positional-only parameters, they would need to execute the module to access any metadata the decorator is setting.</li> <li>Any error with the declaration will be reported only at runtime.</li> <li>It may be more difficult to identify positional-only parameters in long function definitions, as it forces the user to count them to know which is the last one that is impacted by the decorator.</li> <li>The <code class="docutils literal notranslate"><span class="pre">/</span></code> syntax has already been introduced for C functions. This inconsistency will make it more challenging to implement any tools and modules that deal with this syntax — including but not limited to, the argument clinic, the inspect module and the <code class="docutils literal notranslate"><span class="pre">ast</span></code> module.</li> <li>The decorator implementation would likely impose a runtime performance cost, particularly when compared to adding support directly to the interpreter.</li> </ul> </section> <section id="per-argument-marker"> <h3><a class="toc-backref" href="#per-argument-marker" role="doc-backlink">Per-Argument Marker</a></h3> <p>A per-argument marker is another language-intrinsic option. The approach adds a token to each of the parameters to indicate they are positional-only and requires those parameters to be placed together. Example:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="p">(</span><span class="o">.</span><span class="n">arg1</span><span class="p">,</span> <span class="o">.</span><span class="n">arg2</span><span class="p">,</span> <span class="n">arg3</span><span class="p">):</span> </pre></div> </div> <p>Note the dot (i.e., <code class="docutils literal notranslate"><span class="pre">.</span></code>) on <code class="docutils literal notranslate"><span class="pre">.arg1</span></code> and <code class="docutils literal notranslate"><span class="pre">.arg2</span></code>. While this approach may be easier to read, it has been rejected because <code class="docutils literal notranslate"><span class="pre">/</span></code> as an explicit marker is congruent with <code class="docutils literal notranslate"><span class="pre">*</span></code> for keyword-only arguments and is less error-prone.</p> <p>It should be noted that some libraries already use leading underscore <a class="footnote-reference brackets" href="#leading-underscore" id="id18">[12]</a> to conventionally indicate parameters as positional-only.</p> </section> <section id="using-as-a-per-argument-marker"> <h3><a class="toc-backref" href="#using-as-a-per-argument-marker" role="doc-backlink">Using “__” as a Per-Argument Marker</a></h3> <p>Some libraries and applications (like <code class="docutils literal notranslate"><span class="pre">mypy</span></code> or <code class="docutils literal notranslate"><span class="pre">jinja</span></code>) use names prepended with a double underscore (i.e., <code class="docutils literal notranslate"><span class="pre">__</span></code>) as a convention to indicate positional-only parameters. We have rejected the idea of introducing <code class="docutils literal notranslate"><span class="pre">__</span></code> as a new syntax because:</p> <ul class="simple"> <li>It is a backwards-incompatible change.</li> <li>It is not symmetric with how the keyword-only parameters are currently declared.</li> <li>Querying the AST for positional-only parameters would require checking the normal arguments and inspecting their names, whereas keyword-only parameters have a property associated with them (<code class="docutils literal notranslate"><span class="pre">FunctionDef.args.kwonlyargs</span></code>).</li> <li>Every parameter would need to be inspected to know when positional-only arguments end.</li> <li>The marker is more verbose, forcing marking every positional-only parameter.</li> <li>It clashes with other uses of the double underscore prefix like invoking name mangling in classes.</li> </ul> </section> <section id="group-positional-only-parameters-with-parentheses"> <h3><a class="toc-backref" href="#group-positional-only-parameters-with-parentheses" role="doc-backlink">Group Positional-Only Parameters With Parentheses</a></h3> <p>Tuple parameter unpacking is a Python 2 feature which allows the use of a tuple as a parameter in a function definition. It allows a sequence argument to be unpacked automatically. An example is:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">fxn</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="n">c</span><span class="p">),</span> <span class="n">d</span><span class="p">):</span> <span class="k">pass</span> </pre></div> </div> <p>Tuple argument unpacking was removed in Python 3 (<a class="pep reference internal" href="../pep-3113/" title="PEP 3113 – Removal of Tuple Parameter Unpacking">PEP 3113</a>). There has been a proposition to reuse this syntax to implement positional-only parameters. We have rejected this syntax for indicating positional only parameters for several reasons:</p> <ul class="simple"> <li>The syntax is asymmetric with respect to how keyword-only parameters are declared.</li> <li>Python 2 uses this syntax which could raise confusion regarding the behavior of this syntax. This would be surprising to users porting Python 2 codebases that were using this feature.</li> <li>This syntax is very similar to tuple literals. This can raise additional confusion because it can be confused with a tuple declaration.</li> </ul> </section> <section id="after-separator-proposal"> <h3><a class="toc-backref" href="#after-separator-proposal" role="doc-backlink">After Separator Proposal</a></h3> <p>Marking positional-parameters after the <code class="docutils literal notranslate"><span class="pre">/</span></code> was another idea considered. However, we were unable to find an approach which would modify the arguments after the marker. Otherwise, would force the parameters before the marker to be positional-only as well. For example:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="o">/</span><span class="p">,</span> <span class="n">z</span><span class="p">):</span> </pre></div> </div> <p>If we define that <code class="docutils literal notranslate"><span class="pre">/</span></code> marks <code class="docutils literal notranslate"><span class="pre">z</span></code> as positional-only, it would not be possible to specify <code class="docutils literal notranslate"><span class="pre">x</span></code> and <code class="docutils literal notranslate"><span class="pre">y</span></code> as keyword arguments. Finding a way to work around this limitation would add confusion given that at the moment keyword arguments cannot be followed by positional arguments. Therefore, <code class="docutils literal notranslate"><span class="pre">/</span></code> would make both the preceding and following parameters positional-only.</p> </section> </section> <section id="thanks"> <h2><a class="toc-backref" href="#thanks" role="doc-backlink">Thanks</a></h2> <p>Credit for some of the content of this PEP is contained in Larry Hastings’s <a class="pep reference internal" href="../pep-0457/" title="PEP 457 – Notation For Positional-Only Parameters">PEP 457</a>.</p> <p>Credit for the use of <code class="docutils literal notranslate"><span class="pre">/</span></code> as the separator between positional-only and positional-or-keyword parameters go to Guido van Rossum, in a proposal from 2012. <a class="footnote-reference brackets" href="#guido" id="id19">[8]</a></p> <p>Credit for discussion about the simplification of the grammar goes to Braulio Valdivieso.</p> <aside class="footnote-list brackets"> <aside class="footnote brackets" id="numpy-ufuncs" role="doc-footnote"> <dt class="label" id="numpy-ufuncs">[1]<em> (<a href='#id3'>1</a>, <a href='#id10'>2</a>) </em></dt> <dd><a class="reference external" href="https://docs.scipy.org/doc/numpy/reference/ufuncs.html#available-ufuncs">https://docs.scipy.org/doc/numpy/reference/ufuncs.html#available-ufuncs</a></aside> <aside class="footnote brackets" id="scipy-gammaln" role="doc-footnote"> <dt class="label" id="scipy-gammaln">[2]<em> (<a href='#id4'>1</a>, <a href='#id11'>2</a>) </em></dt> <dd><a class="reference external" href="https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.gammaln.html">https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.gammaln.html</a></aside> <aside class="footnote brackets" id="dict" role="doc-footnote"> <dt class="label" id="dict">[<a href="#id2">3</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">[4]<em> (<a href='#id1'>1</a>, <a href='#id8'>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="#id6">5</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="#id7">6</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="#id9">7</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">[8]<em> (<a href='#id14'>1</a>, <a href='#id15'>2</a>, <a href='#id19'>3</a>) </em></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 class="footnote brackets" id="python-ideas-decorator-based" role="doc-footnote"> <dt class="label" id="python-ideas-decorator-based">[9]<em> (<a href='#id13'>1</a>, <a href='#id17'>2</a>) </em></dt> <dd><a class="reference external" href="https://mail.python.org/pipermail/python-ideas/2017-February/044888.html">https://mail.python.org/pipermail/python-ideas/2017-February/044888.html</a></aside> <aside class="footnote brackets" id="posonly-impl" role="doc-footnote"> <dt class="label" id="posonly-impl">[<a href="#id16">10</a>]</dt> <dd><a class="reference external" href="https://github.com/pablogsal/cpython_positional_only">https://github.com/pablogsal/cpython_positional_only</a></aside> <aside class="footnote brackets" id="thread-keyword-to-positional" role="doc-footnote"> <dt class="label" id="thread-keyword-to-positional">[<a href="#id12">11</a>]</dt> <dd><a class="reference external" href="https://mail.python.org/pipermail/python-ideas/2016-January/037874.html">https://mail.python.org/pipermail/python-ideas/2016-January/037874.html</a></aside> <aside class="footnote brackets" id="leading-underscore" role="doc-footnote"> <dt class="label" id="leading-underscore">[<a href="#id18">12</a>]</dt> <dd><a class="reference external" href="https://mail.python.org/pipermail/python-ideas/2018-September/053319.html">https://mail.python.org/pipermail/python-ideas/2018-September/053319.html</a></aside> <aside class="footnote brackets" id="document-positional-only" role="doc-footnote"> <dt class="label" id="document-positional-only">[<a href="#id5">13</a>]</dt> <dd><a class="reference external" href="https://bugs.python.org/issue21314">https://bugs.python.org/issue21314</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-0570.rst">https://github.com/python/peps/blob/main/peps/pep-0570.rst</a></p> <p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0570.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><ul> <li><a class="reference internal" href="#history-of-positional-only-parameter-semantics-in-python">History of Positional-Only Parameter Semantics in Python</a></li> <li><a class="reference internal" href="#problems-without-positional-only-parameters">Problems Without Positional-Only Parameters</a><ul> <li><a class="reference internal" href="#challenges-for-library-authors">Challenges for Library Authors</a></li> <li><a class="reference internal" href="#challenges-for-users-of-an-api">Challenges for Users of an API</a></li> </ul> </li> <li><a class="reference internal" href="#benefits-of-positional-only-parameters">Benefits of Positional-Only Parameters</a><ul> <li><a class="reference internal" href="#empowering-library-authors">Empowering Library Authors</a></li> <li><a class="reference internal" href="#improving-language-consistency">Improving Language Consistency</a></li> </ul> </li> </ul> </li> <li><a class="reference internal" href="#rationale">Rationale</a><ul> <li><a class="reference internal" href="#performance">Performance</a></li> <li><a class="reference internal" href="#maintainability">Maintainability</a></li> <li><a class="reference internal" href="#logical-ordering">Logical ordering</a></li> <li><a class="reference internal" href="#compatibility-for-pure-python-and-c-modules">Compatibility for Pure Python and C Modules</a></li> <li><a class="reference internal" href="#consistency-in-subclasses">Consistency in Subclasses</a></li> <li><a class="reference internal" href="#optimizations">Optimizations</a></li> </ul> </li> <li><a class="reference internal" href="#specification">Specification</a><ul> <li><a class="reference internal" href="#syntax-and-semantics">Syntax and Semantics</a></li> <li><a class="reference internal" href="#full-grammar-specification">Full Grammar Specification</a></li> <li><a class="reference internal" href="#semantic-corner-case">Semantic Corner Case</a></li> <li><a class="reference internal" href="#origin-of-as-a-separator">Origin of “/” as a Separator</a></li> </ul> </li> <li><a class="reference internal" href="#how-to-teach-this">How To Teach This</a><ul> <li><a class="reference internal" href="#positional-or-keyword-arguments">Positional-or-Keyword Arguments</a></li> <li><a class="reference internal" href="#positional-only-parameters">Positional-Only Parameters</a></li> <li><a class="reference internal" href="#keyword-only-arguments">Keyword-Only Arguments</a></li> <li><a class="reference internal" href="#function-examples">Function Examples</a></li> <li><a class="reference internal" href="#recap">Recap</a></li> </ul> </li> <li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li> <li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul> <li><a class="reference internal" href="#do-nothing">Do Nothing</a></li> <li><a class="reference internal" href="#decorators">Decorators</a></li> <li><a class="reference internal" href="#per-argument-marker">Per-Argument Marker</a></li> <li><a class="reference internal" href="#using-as-a-per-argument-marker">Using “__” as a Per-Argument Marker</a></li> <li><a class="reference internal" href="#group-positional-only-parameters-with-parentheses">Group Positional-Only Parameters With Parentheses</a></li> <li><a class="reference internal" href="#after-separator-proposal">After Separator Proposal</a></li> </ul> </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-0570.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>

Pages: 1 2 3 4 5 6 7 8 9 10