Python inspect module: keyword only args Python inspect module: keyword only args python-3.x python-3.x

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 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: 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: