Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Hint: You can adjust the default video playback speed in your account settings.
Hint: You can set your subtitle preferences in your account settings.
Sorry! Looks like there’s an issue with video playback 🙁 This might be due to a temporary outage or because of a configuration issue with your browser. Please refer to our video player troubleshooting guide for assistance.

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.

00:16 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.

00:32 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.

00:45 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,

01:05 ['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.

01:17 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.

01:39 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.

02:40 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.

03:13 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.

03:49 The solution is to set my_list to have a default value of None. Now, None is not a mutable object, and so we aren’t going to be changing it each time.

04:03 Each time we call it without a parameter, we just have None. So we make a check. If my_list is None, then we create a new list and then we append to that.

04:17 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.

04:37 And this is from function_mut_def2 import f.

04:44 If we provide an actual list,

04:51 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.

05:08 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.

05:26 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 None.

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.

05:47 So again, if no argument is provided, my_list has a value of None. The if statement then causes a new empty list to be created.

05:57 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.

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 = None anymore?

def f(my_list=[]):
    my_list.append("###")
    return my_list

print(f())

The above example did exactly the same as my_list = None, etc.

TheArchon on Dec. 14, 2023

The tutorial executes print(f()) twice in a REPL.

Add a second print(f()) to the code above and execute it as a file to get the behavior demonstrated in the tutorial.

Become a Member to join the conversation.