Today we’ll be talking about keyword-only arguments.
If you haven’t read my article on argument matching modes in Python, it’s by all means recommended that you read it first.
Here’s the video version of this article:
As the name suggests, keyword-only arguments must be passed by keyword. It comes in very handy if we need a function that can take an arbitrary number of arguments and also can accept default keyword arguments. Actually, this is a typical use case for keyword-only arguments.
Example 1
Have a look at the following example:
In the function definition we have a * argument that packs an arbitrary number of arguments in a tuple and two optional parameters with values set to 5 and 10.
The function is supposed to just print all the arguments out, separating them with spaces:
>>> def func(*a, b = 5, c = 10):
... print(a, b, c)
...
We can now pass an arbitrary number of arguments to the function. Let’s pass 5:
>>> func(1, 1, 1, 1, 1)
(1, 1, 1, 1, 1) 5 10
What we get in the output is the tuple into which all the arguments were packed plus the default arguments set to 5 and 10 in the function definition.
Now let’s pass one argument. It’s still gonna be packed in a tuple:
>>> func(1)
(1,) 5 10
And now let’s use the function without passing any arguments. We’ll still have the two defaults there:
>>> func()
() 5 10
Now let’s pass 5 arguments followed by the keyword arguments set to different values:
>>> func(1, 1, 1, 1, 1, b = 20, c = 50)
(1, 1, 1, 1, 1) 20 50
Now let’s pass one argument and the keyword argument c set to 80:
>>> func(1, c = 80)
(1,) 5 80
We can also pass just the keyword arguments because the arbitrary number of arguments may also be zero:
>>> func(b = 0, c = 0)
() 0 0
Example 2
As you might have noticed, the keyword-only arguments always follow the * arguments. Have a look at the following example:
Here’s a function that takes a and b as either positional or keyword arguments, then an arbitrary number of arguments packed in the c tuple, then two keyword-only arguments:
>>> def func(a, b, *c, d, e):
... print(a, b, c, d, e)
...
Let’s now pass 1 and 2 for a and b, 3 and 4 for the c tuple and 5 and 6 for the final two arguments. But let’s pass the final two arguments as positional arguments:
>>> func(1, 2, 3, 4, 5, 6)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: func() missing 2 required keyword-only arguments: 'd' and 'e'
It doesn’t work because the arguments following the * arguments must be keyword arguments. So, let’s fix this:
>>> func(1, 2, 3, 4, e = 5, d = 6)
1 2 (3, 4) 6 5
Now it works. By the way, the keyword arguments may be passed in any order.
Example 3
You can also define a function that can’t take an arbitrary number of arguments, but still takes keyword-only arguments. To do that, you just have to pass a * character to the function. This just means that all arguments after the * character must be keyword arguments:
Here’s a function with a * character in the parameter list:
>>> def func(a, b, *, c, d):
... print(a, b, c, d)
...
This means a and b may be either positional or keyword arguments, but c and d must be keyword arguments. If we try to pass c and d as positional arguments, we get an error:
>>> func(4, 5, 6, 7)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: func() takes 2 positional arguments but 4 were given
And this is how it should be done:
>>> func(4, 5, c = 6, d = 7)
4 5 6 7