mirror of
https://github.com/python/cpython.git
synced 2025-07-23 19:25:40 +00:00
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
This commit is contained in:
parent
77f0ed7a42
commit
b76302ddd0
5 changed files with 182 additions and 10 deletions
|
@ -33,7 +33,7 @@ bound into a function.
|
||||||
|
|
||||||
Return the number of free variables in *co*.
|
Return the number of free variables in *co*.
|
||||||
|
|
||||||
.. c:function:: PyCodeObject* PyCode_New(int argcount, int kwonlyargcount, int nlocals, int stacksize, int flags, PyObject *code, PyObject *consts, PyObject *names, PyObject *varnames, PyObject *freevars, PyObject *cellvars, PyObject *filename, PyObject *name, int firstlineno, PyObject *lnotab)
|
.. c:function:: PyCodeObject* PyCode_New(int argcount, int posonlyargcount, int kwonlyargcount, int nlocals, int stacksize, int flags, PyObject *code, PyObject *consts, PyObject *names, PyObject *varnames, PyObject *freevars, PyObject *cellvars, PyObject *filename, PyObject *name, int firstlineno, PyObject *lnotab)
|
||||||
|
|
||||||
Return a new code object. If you need a dummy code object to
|
Return a new code object. If you need a dummy code object to
|
||||||
create a frame, use :c:func:`PyCode_NewEmpty` instead. Calling
|
create a frame, use :c:func:`PyCode_NewEmpty` instead. Calling
|
||||||
|
|
|
@ -236,6 +236,7 @@ PyCode_GetNumFree:PyCodeObject*:co:0:
|
||||||
|
|
||||||
PyCode_New:PyCodeObject*::+1:
|
PyCode_New:PyCodeObject*::+1:
|
||||||
PyCode_New:int:argcount::
|
PyCode_New:int:argcount::
|
||||||
|
PyCode_New:int:posonlyargcount::
|
||||||
PyCode_New:int:kwonlyargcount::
|
PyCode_New:int:kwonlyargcount::
|
||||||
PyCode_New:int:nlocals::
|
PyCode_New:int:nlocals::
|
||||||
PyCode_New:int:stacksize::
|
PyCode_New:int:stacksize::
|
||||||
|
|
|
@ -169,6 +169,9 @@ attributes:
|
||||||
| | | variables (referenced via |
|
| | | variables (referenced via |
|
||||||
| | | a function's closure) |
|
| | | a function's closure) |
|
||||||
+-----------+-------------------+---------------------------+
|
+-----------+-------------------+---------------------------+
|
||||||
|
| | co_posonlyargcount| number of positional only |
|
||||||
|
| | | arguments |
|
||||||
|
+-----------+-------------------+---------------------------+
|
||||||
| | co_kwonlyargcount | number of keyword only |
|
| | co_kwonlyargcount | number of keyword only |
|
||||||
| | | arguments (not including |
|
| | | arguments (not including |
|
||||||
| | | \*\* arg) |
|
| | | \*\* arg) |
|
||||||
|
@ -724,13 +727,9 @@ function.
|
||||||
| Name | Meaning |
|
| Name | Meaning |
|
||||||
+========================+==============================================+
|
+========================+==============================================+
|
||||||
| *POSITIONAL_ONLY* | Value must be supplied as a positional |
|
| *POSITIONAL_ONLY* | Value must be supplied as a positional |
|
||||||
| | argument. |
|
| | argument. Positional only parameters are |
|
||||||
| | |
|
| | those which appear before a ``/`` entry (if |
|
||||||
| | Python has no explicit syntax for defining |
|
| | present) in a Python function definition. |
|
||||||
| | positional-only parameters, but many built-in|
|
|
||||||
| | and extension module functions (especially |
|
|
||||||
| | those that accept only one or two parameters)|
|
|
||||||
| | accept them. |
|
|
||||||
+------------------------+----------------------------------------------+
|
+------------------------+----------------------------------------------+
|
||||||
| *POSITIONAL_OR_KEYWORD*| Value may be supplied as either a keyword or |
|
| *POSITIONAL_OR_KEYWORD*| Value may be supplied as either a keyword or |
|
||||||
| | positional argument (this is the standard |
|
| | positional argument (this is the standard |
|
||||||
|
|
|
@ -483,8 +483,10 @@ A function definition defines a user-defined function object (see section
|
||||||
decorators: `decorator`+
|
decorators: `decorator`+
|
||||||
decorator: "@" `dotted_name` ["(" [`argument_list` [","]] ")"] NEWLINE
|
decorator: "@" `dotted_name` ["(" [`argument_list` [","]] ")"] NEWLINE
|
||||||
dotted_name: `identifier` ("." `identifier`)*
|
dotted_name: `identifier` ("." `identifier`)*
|
||||||
parameter_list: `defparameter` ("," `defparameter`)* ["," [`parameter_list_starargs`]]
|
parameter_list: `defparameter` ("," `defparameter`)* ',' '/' [',' [`parameter_list_no_posonly`]]
|
||||||
: | `parameter_list_starargs`
|
: | `parameter_list_no_posonly`
|
||||||
|
parameter_list_no_posonly: `defparameter` ("," `defparameter`)* ["," [`parameter_list_starargs`]]
|
||||||
|
: | `parameter_list_starargs`
|
||||||
parameter_list_starargs: "*" [`parameter`] ("," `defparameter`)* ["," ["**" `parameter` [","]]]
|
parameter_list_starargs: "*" [`parameter`] ("," `defparameter`)* ["," ["**" `parameter` [","]]]
|
||||||
: | "**" `parameter` [","]
|
: | "**" `parameter` [","]
|
||||||
parameter: `identifier` [":" `expression`]
|
parameter: `identifier` [":" `expression`]
|
||||||
|
|
|
@ -519,6 +519,176 @@ and of course it would print:
|
||||||
Note that the order in which the keyword arguments are printed is guaranteed
|
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.
|
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:
|
.. _tut-arbitraryargs:
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue