Here’s another article in the Functions in Python series. It’s about mutable optional parameters.
If you haven’t read the previous parts yet, feel free to do so. Here they are:
In the previous article we were talking about optional parameters. There’s one more thing to optional parameters we should be aware of. The default value is only evaluated the first time the function is called. If the optional parameter is a mutable type, like a list or dictionary, and it’s changed in the function, the change will propagate through all the following calls. This is what we are going to talk about in this article.
Let’s start right away with an example:
def list_appender(item, items = []):
items.append(item)
return items
print(list_appender("hello"))
print(list_appender("salut"))
print(list_appender("hallo"))
print(list_appender("hola"))
Here we have a function that has one optional parameter, an empty list. In the function the object passed as the first parameter, which is mandatory, is appended to the list. When the function is called for the first time, the optional parameter is evaluated. In the function the element “hello” is appended to the list and the list with the “hello” string is returned. But when the function is called for the second time, the optional parameter is not evaluated again, so the function works on the list with the element appended before, not on an empty list like the first time. In the following calls the new element is appended to the list which already contains all the elements appended in the earlier function calls. Here’s the output:
['hello']
['hello', 'salut']
['hello', 'salut', 'hallo']
['hello', 'salut', 'hallo', 'hola']
So, the default parameter is shared between subsequent calls. This is how mutable optional parameters work. If it’s not what you want, you can get around it for example like so:
def list_appender(item, items = None):
if items is None: items = []
items.append(item)
return items
print(list_appender("hello"))
print(list_appender("salut"))
print(list_appender("hallo"))
print(list_appender("hola"))
Now, if the optional parameter is not passed to the function, the default value will be None. Then we check if the parameter is None, and if so, an empty list is assigned to it. Here’s the output:
['hello']
['salut']
['hallo']
['hola']
By the way, have a look at this line of code again:
if items is None: items = []
Here we have a whole conditional block on one line. This is a so-called single statement suite and I have an article on single statement suites, if you’d like to read it.