21
#1 Anti-Pattern - Mutable Default Arguments
If you are not sure what a mutable default argument is, please read the full article as it can save you hours of
debugging.
Consider the following code example below.
def add_fruit(fruit, box=[]):
box.append(fruit)
return box
Let's understand step by step what is happening:
- We are creating a function to add fruits(str) in a box(list)
- There is a
add_fruit
function which is responsible for adding thefruit
- This function takes 2 arguments:
fruit
andbox
- Attention! : The second argument here is a mutable default argument.
An argument in a function with default value as mutable.
In short, Python has both mutable and immutable types. The difference being:
- mutables can be modified
- immutables can't be modified.
For eg: Tuple is an immutable type. If we define a tuple like this:
weekends = ('saturday', 'sunday',)
weekends[0] = 'Monday' # TypeError: 'tuple' object does not support item assignment
An immutable type can never be modified.
let's modify our code and create a couple of boxes, i.e. red box and yellow box
def add_fruit(fruit, box=[]):
box.append(fruit)
return box
red_box = add_fruit("apple")
print(f"red box: {red_box}")
yellow_box = add_fruit("mango")
print(f"yellow box: {yellow_box}")
red box: ["apple"]
yellow box: ["mango"]
Actually, you get the following output:
red box: ["apple"]
yellow box: ["apple", "mango"]
Wait? What? We never added apple in the yellow box.
A new list is created once when the function is defined, and the same list is used in each successive call.
Python’s default arguments are evaluated once when the function is defined. This means that if you use a mutable default argument and mutate it, you will and have mutated that object for all future calls to the function as well.
We will get the same result for other mutable types also(For eg: dict).
If your function needs to have a default argument for a mutable type, then default it with None and also add a check for same.
Let's modify our add_fruit
function:
def add_fruit(fruit, box=None):
if box is None:
box = []
box.append(fruit)
return box
red_box = add_fruit("apple")
print(f"red box: {red_box}")
yellow_box = add_fruit("mango")
print(f"yellow box: {yellow_box}")
This extra check can saves hours of debugging!
It's always a best practice to not use mutable default arguments. Instead, try adding an extra comparison check with
None to handle default arguments which are mutable.
21