peps/pep-3102/index.html

283 lines
16 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!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 3102 Keyword-Only Arguments | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-3102/">
<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 3102 Keyword-Only Arguments | peps.python.org'>
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-3102/">
<meta property="og:site_name" content="Python Enhancement Proposals (PEPs)">
<meta property="og:image" content="https://peps.python.org/_static/og-image.png">
<meta property="og:image:alt" content="Python PEPs">
<meta property="og:image:width" content="200">
<meta property="og:image:height" content="200">
<meta name="description" content="Python Enhancement Proposals (PEPs)">
<meta name="theme-color" content="#3776ab">
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all">
<title>Following system colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="9"></circle>
<path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path>
</svg>
</symbol>
<symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all">
<title>Selected dark colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path>
</svg>
</symbol>
<symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all">
<title>Selected light colour scheme</title>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
</symbol>
</svg>
<script>
document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto"
</script>
<section id="pep-page-section">
<header>
<h1>Python Enhancement Proposals</h1>
<ul class="breadcrumbs">
<li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> &raquo; </li>
<li><a href="../pep-0000/">PEP Index</a> &raquo; </li>
<li>PEP 3102</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 3102 Keyword-Only Arguments</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Talin &lt;viridia&#32;&#97;t&#32;gmail.com&gt;</dd>
<dt class="field-even">Status<span class="colon">:</span></dt>
<dd class="field-even"><abbr title="Accepted and implementation complete, or no longer active">Final</abbr></dd>
<dt class="field-odd">Type<span class="colon">:</span></dt>
<dd class="field-odd"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd>
<dt class="field-even">Created<span class="colon">:</span></dt>
<dd class="field-even">22-Apr-2006</dd>
<dt class="field-odd">Python-Version<span class="colon">:</span></dt>
<dd class="field-odd">3.0</dd>
<dt class="field-even">Post-History<span class="colon">:</span></dt>
<dd class="field-even">28-Apr-2006, 19-May-2006</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="#rationale">Rationale</a></li>
<li><a class="reference internal" href="#specification">Specification</a></li>
<li><a class="reference internal" href="#function-calling-behavior">Function Calling Behavior</a></li>
<li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</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 a change to the way that function arguments are
assigned to named parameter slots. In particular, it enables the
declaration of “keyword-only” arguments: arguments that can only
be supplied by keyword and which will never be automatically
filled in by a positional argument.</p>
</section>
<section id="rationale">
<h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2>
<p>The current Python function-calling paradigm allows arguments to
be specified either by position or by keyword. An argument can be
filled in either explicitly by name, or implicitly by position.</p>
<p>There are often cases where it is desirable for a function to take
a variable number of arguments. The Python language supports this
using the varargs syntax (<code class="docutils literal notranslate"><span class="pre">*name</span></code>), which specifies that any
left over arguments be passed into the varargs parameter as a
tuple.</p>
<p>One limitation on this is that currently, all of the regular
argument slots must be filled before the vararg slot can be.</p>
<p>This is not always desirable. One can easily envision a function
which takes a variable number of arguments, but also takes one
or more options in the form of keyword arguments. Currently,
the only way to do this is to define both a varargs argument,
and a keywords argument (<code class="docutils literal notranslate"><span class="pre">**kwargs</span></code>), and then manually extract
the desired keywords from the dictionary.</p>
</section>
<section id="specification">
<h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2>
<p>Syntactically, the proposed changes are fairly simple. The first
change is to allow regular arguments to appear after a varargs
argument:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">sortwords</span><span class="p">(</span><span class="o">*</span><span class="n">wordlist</span><span class="p">,</span> <span class="n">case_sensitive</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
<span class="o">...</span>
</pre></div>
</div>
<p>This function accepts any number of positional arguments, and it
also accepts a keyword option called case_sensitive. This
option will never be filled in by a positional argument, but
must be explicitly specified by name.</p>
<p>Keyword-only arguments are not required to have a default value.
Since Python requires that all arguments be bound to a value,
and since the only way to bind a value to a keyword-only argument
is via keyword, such arguments are therefore required keyword
arguments. Such arguments must be supplied by the caller, and
they must be supplied via keyword.</p>
<p>The second syntactical change is to allow the argument name to
be omitted for a varargs argument. The meaning of this is to
allow for keyword-only arguments for functions that would not
otherwise take a varargs argument:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">compare</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="o">...</span>
</pre></div>
</div>
<p>The reasoning behind this change is as follows. Imagine for a
moment a function which takes several positional arguments, as
well as a keyword argument:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">compare</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="o">...</span>
</pre></div>
</div>
<p>Now, suppose you wanted to have key be a keyword-only argument.
Under the above syntax, you could accomplish this by adding a
varargs argument immediately before the keyword argument:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">compare</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="o">*</span><span class="n">ignore</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="o">...</span>
</pre></div>
</div>
<p>Unfortunately, the ignore argument will also suck up any
erroneous positional arguments that may have been supplied by the
caller. Given that wed prefer any unwanted arguments to raise an
error, we could do this:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">compare</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="o">*</span><span class="n">ignore</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="k">if</span> <span class="n">ignore</span><span class="p">:</span> <span class="c1"># If ignore is not empty</span>
<span class="k">raise</span> <span class="ne">TypeError</span>
</pre></div>
</div>
<p>As a convenient shortcut, we can simply omit the ignore name,
meaning dont allow any positional arguments beyond this point.</p>
<p>(Note: After much discussion of alternative syntax proposals, the
BDFL has pronounced in favor of this single star syntax for
indicating the end of positional parameters.)</p>
</section>
<section id="function-calling-behavior">
<h2><a class="toc-backref" href="#function-calling-behavior" role="doc-backlink">Function Calling Behavior</a></h2>
<p>The previous section describes the difference between the old
behavior and the new. However, it is also useful to have a
description of the new behavior that stands by itself, without
reference to the previous model. So this next section will
attempt to provide such a description.</p>
<p>When a function is called, the input arguments are assigned to
formal parameters as follows:</p>
<ul class="simple">
<li>For each formal parameter, there is a slot which will be used
to contain the value of the argument assigned to that
parameter.</li>
<li>Slots which have had values assigned to them are marked as
filled. Slots which have no value assigned to them yet are
considered empty.</li>
<li>Initially, all slots are marked as empty.</li>
<li>Positional arguments are assigned first, followed by keyword
arguments.</li>
<li>For each positional argument:<ul>
<li>Attempt to bind the argument to the first unfilled
parameter slot. If the slot is not a vararg slot, then
mark the slot as filled.</li>
<li>If the next unfilled slot is a vararg slot, and it does
not have a name, then it is an error.</li>
<li>Otherwise, if the next unfilled slot is a vararg slot then
all remaining non-keyword arguments are placed into the
vararg slot.</li>
</ul>
</li>
<li>For each keyword argument:<ul>
<li>If there is a parameter with the same name as the keyword,
then the argument value is assigned to that parameter slot.
However, if the parameter slot is already filled, then that
is an error.</li>
<li>Otherwise, if there is a keyword dictionary argument,
the argument is added to the dictionary using the keyword
name as the dictionary key, unless there is already an
entry with that key, in which case it is an error.</li>
<li>Otherwise, if there is no keyword dictionary, and no
matching named parameter, then it is an error.</li>
</ul>
</li>
<li>Finally:<ul>
<li>If the vararg slot is not yet filled, assign an empty tuple
as its value.</li>
<li>For each remaining empty slot: if there is a default value
for that slot, then fill the slot with the default value.
If there is no default value, then it is an error.</li>
</ul>
</li>
</ul>
<p>In accordance with the current Python implementation, any errors
encountered will be signaled by raising <code class="docutils literal notranslate"><span class="pre">TypeError</span></code>. (If you want
something different, thats a subject for a different PEP.)</p>
</section>
<section id="backwards-compatibility">
<h2><a class="toc-backref" href="#backwards-compatibility" role="doc-backlink">Backwards Compatibility</a></h2>
<p>The function calling behavior specified in this PEP is a superset
of the existing behavior - that is, it is expected that any
existing programs will continue to work.</p>
</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-3102.rst">https://github.com/python/peps/blob/main/peps/pep-3102.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-3102.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="#rationale">Rationale</a></li>
<li><a class="reference internal" href="#specification">Specification</a></li>
<li><a class="reference internal" href="#function-calling-behavior">Function Calling Behavior</a></li>
<li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</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-3102.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>