TL;DR: Keyword-only arguments are not the same as normal keyword arguments.
Keyword-only arguments are arguments that come after *args
and before **kwargs
in a function call. As an example, consider this generic function header:
def func(arg, *args, kwonly, **kwargs):
In the above, kwonly
takes a keyword-only argument. This means that you must supply its name when giving it a value. In other words, you must explicitly write:
func(..., kwonly=value, ...)
instead of just passing a value:
func(..., value, ...)
To explain better, consider this sample call of the function given above:
func(1, 2, kwonly=3, kw=4)
When Python interprets this call, it will:
Assign arg
to 1
because its position in the function signature matches the position of 1
in the call.
Place 2
in *args
because *args
collects any extra positional arguments and 2
is extra.
Assign kwonly
to 3
because we have (as is necessary) explicitly told it to. Note that if we had done this instead:
func(1, 2, 3, kw=4)
3
would also be placed in *args
and a TypeError
would be raised for not supplying an argument to kwonly
(since we did not give it a default value in this case).
Place kw=4
in **kwargs
because it is an extra keyword argument, which are collected by **kwargs
.
Below is a demonstration of what I said above:
>>> def func(arg, *args, kwonly, **kwargs):
... print('arg:', arg)
... print('args:', args)
... print('kwonly:', kwonly)
... print('kwargs:', kwargs)
...
>>> func(1, 2, kwonly=3, kw=4)
arg: 1
args: (2,)
kwonly: 3
kwargs: {'kw': 4}
>>>
>>> func(1, 2, 3, kw=4) # Should have written: 'kwonly=3'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: func() missing 1 required keyword-only argument: 'kwonly'
>>>
Basically, you can look at keyword-only arguments as keyword arguments where you must supply the name of the parameter when giving them a value. A positional value will not suffice, as with normal keyword arguments.
>>> def func(kw=None):
... print('kw:', kw)
...
>>> func(kw=1)
kw: 1
>>> func(1) # Do not need the name in this case.
kw: 1
>>>
>>> def func(*, kwonly=None):
... print('kwonly:', kwonly)
...
>>> func(kwonly=1)
kwonly: 1
>>> func(1) # Always need the name with keyword-only arguments.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: func() takes 0 positional arguments but 1 was given
>>>
Finally, I know that some people are thinking "Why have keyword-only arguments anyways?" The answer is simply that they make things more readable in some cases (especially with functions that take a variable number of arguments).
As an example, consider the built-in max
function and its keyword-only key
argument. What is more readable to you? Doing something like this:
max(lambda x: -x, arg1, arg2, arg3)
and having people remember that the first argument to max
is always the key function or doing this:
max(arg1, arg2, arg3, key=lambda x: -x)
and making it clear to everyone that lambda x: -x
is your key function. Plus, making key
a keyword-only argument allows you to simply omit the key function if you do not need one:
max(arg1, arg2, arg3)
instead of doing:
max(None, arg1, arg2, arg3)
For more information, you can check out these sources: