Python language basics 31: mutable objects as default arguments
July 19, 2015 Leave a comment
Introduction
In the previous post we discussed how to provide optional arguments to a function. We saw how easy it was to assign a default value to a function argument using the assignment operator ‘=’. The caller could optionally ignore those arguments so that the default ones would be used within the function body. Alternatively the caller could override the defaults and provide its own argument values.
In this post we’ll discuss an additional facet of optional function arguments. Optional arguments are evaluated only once along with the function. This can cause unexpected results when mutable objects are passed as default arguments.
Mutable default arguments
Let’s first return to our previous example with 2 default arguments:
def multiply(base, multiplier=2, show_greeting=True): if show_greeting: print("Welcome to the multiply function") return base * multiplier
When the multiply function is executed for the first time then all default arguments are evaluated along with the function and its name. Multiplier will be set to 2 and show_greeting to True. These values are not evaluated upon subsequent function executions.
An implication is that you’ll need to take precautions when using mutable objects as default function arguments. Recall our previous example from this post where we discussed the dangers of object references within functions:
def modify_dictionary(dictionary): dictionary["XL"] = "Extra large" return dictionary
Let’s turn this into a modify_list function and have an empty list as an optional input parameter:
def modify_list(list_param=[]): list_param.append("Default") return list_param
Let’s call this function and let the default value take over:
l1 = modify_list() print(l1)
This prints…
[‘Default’]
…as expected.
However, let’s call the same function over and over again:
l1 = modify_list() l1 = modify_list() l1 = modify_list() print(l1)
This prints…
[‘Default’, ‘Default’, ‘Default’]
…which is not really what we’ve expected.
What happens is that list_param=[] is evaluated once when modify_list is executed for the first time. It is created as an empty list like it says in the function signature. Then the list gets a single element “Default” and is returned. The second time the function is executed the default argument is not re-evaluated to an empty list. It is already stored in memory as a list which contains a single element “Default” hence it will be used within the function. It gets one more element called “Default”. The happens upon subsequent calls.
A consequence is that you should always try to rely on immutable objects such as strings or numbers for default arguments.
Read the next post of this series here.
Read all Python-related posts on this blog here.