The Python positional-only parameter has been introduced with the Python 3.8 release. It is a way to specify which parameters must be positional-only arguments – i.e. which parameters cannot be given as keyword-parameters. It uses the /
parameter syntax. Elements positioned on the left side will be then turned into positional-only parameters.
def f(a, b, /, c): ...
The above method will only accepts calls of the following form:
python> f(1, 2, 3)
python> f(1, 2, c=3)
Note: c
can be either given a position or keyword argument.
On the contrary, the following calls will raise a TypeError: f() got some positional-only arguments passed as keyword arguments
error as a
and b
– being on the left of /
– cannot be exposed as possible keyword-arguments:
python> f(1, b=2, 3)
python> f(1, b=2, c=3)
python> f(a=1, b=2, 3)
Use cases
The /
positional-only parameter syntax is helpful in the following use-cases:
-
It precludes keyword arguments from being used when the parameter’s name is not necessary, confusing or misleading e.g.
len(obj=my_list)
. As stated in the documentation, theobj
keyword argument would here impairs readability. -
It allows the name of the parameter to be changed in the future without introducing breaking changes in he client as they can still be passed through
**kwargs
to be used in two ways:
def transform(name, /, **kwargs):
print(name.upper())
In the above snippet, you can access the name
‘s value either using name
or kwargs.get("name")
.
Last but not the least, it can also be used to prevent overwriting pre-set keyword-arguments in methods that still need to accept arbitrary keyword arguments (via kwargs
):
def initialize(name="unknown", /, **kwargs):
print(name, kwargs)
The name
keyword-argument is protected and could not be overwritten, even if mistakenly captured a second time by the kwargs
argument:
python> initialize(name="olivier")
unknown {'name': 'olivier'}
Notes:
- Python does not allow positional arguments after keyword arguments because of the left-side/right-side of the
/
operator thingy. - Python does not allow positional arguments after keyword arguments because of the left-side/right-side of the
*
operator thingy. *args
are collecting as positional arguments.**kwargs
are collecting as keyword-arguments.