Each programming language has its own peculiarities - knowing these will make your code more reliable, and you will avoid unexpected behaviors and/or bugs.

In Python, one such peculiarity, that I learned recently, is that you should not use mutable objects as default arguments.

Let’s see why.

Example

You want a function that appends a number to a list. If the list is not passed, it appends data to a newly created list.

Should we use an empty list as the default argument?

1
2
3
def append_numbers(my_numbers=[]):
	my_numbers.append(5)
	return my_numbers

Running it works just fine, for now.

1
2
3
my_numbers = [10]
print(append_numbers(my_numbers))
>>> [5, 10] # So far so good

Let’s run the function with the default argument this time.

1
2
print(append_numbers())
>>> [10] # Expected

Everything is working. Let’s run it again. Now we’re getting some strange behavior.

It keeps returning a list with more and more numbers, why?

The problem

The moment we define our function, the default object is created. Every time we don’t pass an argument, this object is reused. This only applies to mutable objects.

Solution

Instead of passing an empty list as an argument, pass None instead. Then in your function, check if it is None and create an object, if necessary.

1
2
3
4
5
def append_numbers(my_numbers=None): # default is None
	if my_numbers is None:
		my_numbers = [] # if it was None, we create a new list
	my_numbers.append(10)
	return my_numbers

Now the object will be created each time the function is executed.