Python inspect module: keyword only args
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
to1
because its position in the function signature matches the position of1
in the call.Place
2
in*args
because*args
collects any extra positional arguments and2
is extra.Assign
kwonly
to3
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 aTypeError
would be raised for not supplying an argument tokwonly
(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: 1args: (2,)kwonly: 3kwargs: {'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: