If we want to make an argument optional, rather than creating a second method with a different set of arguments, we can specify a default value in a single method, using an equals sign. If the calling code does not supply this argument, it will be assigned a default value. However, the calling code can still choose to override the default by passing in a different value. Often, a default value of None, or an empty string or list, is suitable.
Here's a function definition with default arguments:
def default_arguments(x, y, z, a="Some String", b=False): pass
The first three arguments are still mandatory and must be passed by the calling code. The last two parameters have default arguments supplied.
There are several ways we can call this function. We can supply all arguments in order, as though all the arguments were positional arguments, as can be seen in the following::
default_arguments("a string", variable, 8, "", True)
Alternatively, we can supply just the mandatory arguments in order, leaving the keyword arguments to be assigned their default values:
default_arguments("a longer string", some_variable, 14)
We can also use the equals sign syntax when calling a function to provide values in a different order, or to skip default values that we aren't interested in. For example, we can skip the first keyword arguments and supply the second one:
default_arguments("a string", variable, 14, b=True)
Surprisingly, we can even use the equals sign syntax to mix up the order of positional arguments, so long as all of them are supplied:
>>> default_arguments(y=1,z=2,x=3,a="hi") 3 1 2 hi False
You may occasionally find it useful to make a keyword-only argument, that is, an argument that must be supplied as a keyword argument. You can do that by placing a * before the keyword-only arguments:
def kw_only(x, y='defaultkw', *, a, b='only'):
print(x, y, a, b)
This function has one positional argument, x, and three keyword arguments, y, a, and b. x and y are both mandatory, but a can only be passed as a keyword argument. y and b are both optional with default values, but if b is supplied, it can only be a keyword argument.
This function fails if you don't pass a:
>>> kw_only('x')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: kw_only() missing 1 required keyword-only argument: 'a'
It also fails if you pass a as a positional argument:
>>> kw_only('x', 'y', 'a')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: kw_only() takes from 1 to 2 positional arguments but 3 were given
But you can pass a and b as keyword arguments:
>>> kw_only('x', a='a', b='b')
x defaultkw a b
With so many options, it may seem hard to pick one, but if you think of the positional arguments as an ordered list, and keyword arguments as sort of like a dictionary, you'll find that the correct layout tends to fall into place. If you need to require the caller to specify an argument, make it mandatory; if you have a sensible default, then make it a keyword argument. Choosing how to call the method normally takes care of itself, depending on which values need to be supplied, and which can be left at their defaults. Keyword-only arguments are relatively rare, but when the use case comes up, they can make for a more elegant API.
One thing to take note of with keyword arguments is that anything we provide as a default argument is evaluated when the function is first interpreted, not when it is called. This means we can't have dynamically generated default values. For example, the following code won't behave quite as expected:
number = 5 def funky_function(number=number): print(number) number=6 funky_function(8) funky_function() print(number)
If we run this code, it outputs the number 8 first, but then it outputs the number 5 for the call with no arguments. We had set the variable to the number 6, as evidenced by the last line of output, but when the function is called, the number 5 is printed; the default value was calculated when the function was defined, not when it was called.
This is tricky with empty containers such as lists, sets, and dictionaries. For example, it is common to ask calling code to supply a list that our function is going to manipulate, but the list is optional. We'd like to make an empty list as a default argument. We can't do this; it will create only one list, when the code is first constructed, demonstrated as follows::
//DON'T DO THIS
>>> def hello(b=[]): ... b.append('a') ... print(b) ... >>> hello() ['a'] >>> hello() ['a', 'a']
Whoops, that's not quite what we expected! The usual way to get around this is to make the default value None, and then use the iargument = argument if argument else [] idiom inside the method. Pay close attention!