Mutable Default Parameter Values
00:00 Let’s take a look at what can happen if you try to use a mutable object as a default parameter value in Python. This is a very classic example to demonstrate what’s happening with default values and mutable objects.
I have a function that’s going to append a string of three hashtags (
'###') to whatever list is passed as a parameter. And if it doesn’t have a parameter, then an empty list is created and the hashtag string is appended to that.
Let’s go ahead and take a look at what’s happening here. I’ve put this in a file called
function_mut_def for “function mutable default.” It’s the same function we saw on that previous slide.
Let’s go ahead and import it and use it! So, from
function_mut_def, let’s import our function. And if I provide a list to this function,
['foo', 'bar', 'baz'], we have provided a list and so the function
f() is going to take that list and append that string of hashtags to the end of it.
It doesn’t particularly care what the list looks like. If I give it a list of numbers,
f() says, “Okay! I’ll append the string to the end of that list.” And if I don’t provide a list,
f() is going to take its default value of an empty list and append the
'###' string to it.
And everything seems to be working just the way we expected until we call
f() without an argument a second time. We were expecting
f() to take an empty list and append the
'###' string to it, but that’s not what happened.
01:58 It took the previous list and keeps appending hashtags to that. Well, why is that? And how do we fix this to behave the way we want it to?
02:13 So, what’s happening here? In Python, the default value for a parameter value is defined only once. So when we imported that module and that function, Python executed it in a way that simply identified the name of the function, the name of the parameter, and its default value, and then it read the rest of the body of that function.
In other words, when we were at this point after the
import statement, the parameter
my_list already had the empty list value. If we provided a list, that argument replaced this one.
03:00 However, if we didn’t, then it continued to use the list that had been defined when the function’s definition statement was first executed.
So, the default value isn’t redefined. It takes that first definition and continues to use it. Every time we call
f() without a parameter value, we’re performing
.append() on that same list.
03:27 So, what’s a better way to write that function to use a new list each time?
03:36 And again, this is a well-known problem with a well-known solution. Like I said, you can probably search Real Python and find this particular example in other courses and in other articles.
The solution is to set
my_list to have a default value of
None is not a mutable object, and so we aren’t going to be changing it each time.
Each time we call it without a parameter, we just have
None. So we make a check. If
None, then we create a new list and then we append to that.
And so this particular version has the behavior that we wanted. I called this
function_mut_def2. Brilliant name, I know. Let’s quit this and restart our REPL.
And this is
from function_mut_def2 import f.
04:44 If we provide an actual list,
we will append the
'###' string to that list. If I don’t provide a list, then
my_list, the parameter, still has a value of
None, since that’s the default value to use.
And each time the default value is
None, then we create a new list and then we append to whatever that list is. The point to make is that
my_list isn’t defined to a list at the definition execution.
my_list is set to
None as the default value, and that’s not mutable, so every time we call it without an argument, it comes back to this value of
05:36 It doesn’t have a list at this point to use. And so we can actually see that this does have the behavior that we want.
So again, if no argument is provided,
my_list has a value of
if statement then causes a new empty list to be created.
And we saw that if we do provide an argument, then
my_list is assigned to use that, and that list is modified appropriately.
06:07 The next few lessons are going to talk about how Python passes objects to a function and what you’re able to do with them, and compare it to other languages and how they choose to modify or not modify a parameter value that’s given to it.
Become a Member to join the conversation.
Brandon Hopkins on April 21, 2023
Everytime I call the empty function, it returns a new list
[###], rather than adds to it. Perhaps Python has fixed this? No need to put
my_list = Noneanymore?
The above example did exactly the same as
my_list = None, etc.