summaryrefslogtreecommitdiffstats
path: root/Doc/tutorial
diff options
context:
space:
mode:
authorPablo Galindo <Pablogsal@gmail.com>2019-05-28 23:45:32 (GMT)
committerCarol Willing <carolcode@willingconsulting.com>2019-05-28 23:45:32 (GMT)
commitb76302ddd0896cb39ce69909349b53db6e7776e2 (patch)
tree5f9a80489decdb07f40e97cf618d62f0ce5b4930 /Doc/tutorial
parent77f0ed7a42606d03ebfe48ab152caf0d796d6540 (diff)
downloadcpython-b76302ddd0896cb39ce69909349b53db6e7776e2.zip
cpython-b76302ddd0896cb39ce69909349b53db6e7776e2.tar.gz
cpython-b76302ddd0896cb39ce69909349b53db6e7776e2.tar.bz2
bpo-36540: Documentation for PEP570 - Python positional only arguments (#13202)
* bpo-36540: Documentation for PEP570 - Python positional only arguments * fixup! bpo-36540: Documentation for PEP570 - Python positional only arguments * Update reference for compound statements * Apply suggestions from Carol Co-Authored-By: Carol Willing <carolcode@willingconsulting.com> * Update Doc/tutorial/controlflow.rst Co-Authored-By: Carol Willing <carolcode@willingconsulting.com> * Add extra bullet point and minor edits
Diffstat (limited to 'Doc/tutorial')
-rw-r--r--Doc/tutorial/controlflow.rst170
1 files changed, 170 insertions, 0 deletions
diff --git a/Doc/tutorial/controlflow.rst b/Doc/tutorial/controlflow.rst
index cfb9645..813b7ca 100644
--- a/Doc/tutorial/controlflow.rst
+++ b/Doc/tutorial/controlflow.rst
@@ -519,6 +519,176 @@ and of course it would print:
Note that the order in which the keyword arguments are printed is guaranteed
to match the order in which they were provided in the function call.
+Special parameters
+------------------
+
+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.
+
+A function definition may look like:
+
+.. code-block:: none
+
+ def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
+ ----------- ---------- ----------
+ | | |
+ | Positional or keyword |
+ | - Keyword only
+ -- Positional only
+
+where ``/`` and ``*`` 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.
+
+-------------------------------
+Positional-or-Keyword Arguments
+-------------------------------
+
+If ``/`` and ``*`` are not present in the function definition, arguments may
+be passed to a function by position or by keyword.
+
+--------------------------
+Positional-Only Parameters
+--------------------------
+
+Looking at this in a bit more detail, it is possible to mark certain parameters
+as *positional-only*. If *positional-only*, the parameters' order matters, and
+the parameters cannot be passed by keyword. Positional-only parameters are
+placed before a ``/`` (forward-slash). The ``/`` is used to logically
+separate the positional-only parameters from the rest of the parameters.
+If there is no ``/`` in the function definition, there are no positional-only
+parameters.
+
+Parameters following the ``/`` may be *positional-or-keyword* or *keyword-only*.
+
+----------------------
+Keyword-Only Arguments
+----------------------
+
+To mark parameters as *keyword-only*, indicating the parameters must be passed
+by keyword argument, place an ``*`` in the arguments list just before the first
+*keyword-only* parameter.
+
+-----------------
+Function Examples
+-----------------
+
+Consider the following example function definitions paying close attention to the
+markers ``/`` and ``*``::
+
+ >>> def standard_arg(arg):
+ ... print(arg)
+ ...
+ >>> def pos_only_arg(arg, /):
+ ... print(arg)
+ ...
+ >>> def kwd_only_arg(*, arg):
+ ... print(arg)
+ ...
+ >>> def combined_example(pos_only, /, standard, *, kwd_only):
+ ... print(pos_only, standard, kwd_only)
+
+
+The first function definition, ``standard_arg``, the most familiar form,
+places no restrictions on the calling convention and arguments may be
+passed by position or keyword::
+
+ >>> standard_arg(2)
+ 2
+
+ >>> standard_arg(arg=2)
+ 2
+
+The second function ``pos_only_arg`` is restricted to only use positional
+parameters as there is a ``/`` in the function definition::
+
+ >>> pos_only_arg(1)
+ 1
+
+ >>> pos_only_arg(arg=1)
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in <module>
+ TypeError: pos_only_arg() got an unexpected keyword argument 'arg'
+
+The third function ``kwd_only_args`` only allows keyword arguments as indicated
+by a ``*`` in the function definition::
+
+ >>> kwd_only_arg(3)
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in <module>
+ TypeError: kwd_only_arg() takes 0 positional arguments but 1 was given
+
+ >>> kwd_only_arg(arg=3)
+ 3
+
+And the last uses all three calling conventions in the same function
+definition::
+
+ >>> combined_example(1, 2, 3)
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in <module>
+ TypeError: combined_example() takes 2 positional arguments but 3 were given
+
+ >>> combined_example(1, 2, kwd_only=3)
+ 1 2 3
+
+ >>> combined_example(1, standard=2, kwd_only=3)
+ 1 2 3
+
+ >>> combined_example(pos_only=1, standard=2, kwd_only=3)
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in <module>
+ TypeError: combined_example() got an unexpected keyword argument 'pos_only'
+
+
+Finally, consider this function definition which has a potential collision between the positional argument ``name`` and ``**kwds`` which has ``name`` as a key::
+
+ def foo(name, **kwds):
+ return 'name' in kwds
+
+There is no possible call that will make it return ``True`` as the keyword ``'name'``
+will always to bind to the first parameter. For example::
+
+ >>> foo(1, **{'name': 2})
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in <module>
+ TypeError: foo() got multiple values for argument 'name'
+ >>>
+
+But using ``/`` (positional only arguments), it is possible since it allows ``name`` as a positional argument and ``'name'`` as a key in the keyword arguments::
+
+ def foo(name, /, **kwds):
+ return 'name' in kwds
+ >>> foo(1, **{'name': 2})
+ True
+
+In other words, the names of positional-only parameters can be used in
+``**kwds`` without ambiguity.
+
+-----
+Recap
+-----
+
+The use case will determine which parameters to use in the function definition::
+
+ def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
+
+As guidance:
+
+* Use positional-only if you want the name of the parameters to not be
+ available to the user. This is useful when parameter names have no real
+ meaning, if you want to enforce the order of the arguments when the function
+ is called or if you need to take some positional parameters and arbitrary
+ keywords.
+* Use keyword-only when names have meaning and the function definition is
+ more understandable by being explicit with names or you want to prevent
+ users relying on the position of the argument being passed.
+* For an API, use positional-only to prevent prevent breaking API changes
+ if the parameter's name is modified in the future.
.. _tut-arbitraryargs: