Code Review · Python · Correctness
Python Code Review: Mutable Default Argument
Review a Python function that accidentally shares a default list across calls.
Code Review Exercise
An interviewer shows you this Python function and asks you to review it. What issues do you see?
def add_user(user, users=[]):
users.append(user)
return users
print(add_user("Alice"))
print(add_user("Bob"))What Actually Happens
Many people expect each call to start with a new empty list. But the default list is created once when the function is defined, not each time the function is called.
['Alice']
['Alice', 'Bob']The second call reuses the same list from the first call. That means state leaks between function calls.
Review Findings
Issue #1: Mutable default argument
The default value users=[] is a list. Lists are mutable, and Python creates default argument objects only once when the function is defined.
Issue #1: Mutable default argument
Each call without the users argument shares the same list. This makes the function behavior depend on previous calls, which is surprising and bug-prone.77
Issue #1: Mutable default argument
The function both appends to a list and returns the list. In a real code review, you may ask whether this function should mutate an existing list or create a new one.
Why This Happens
Python evaluates default argument values at function definition time. For immutable values like strings, numbers, or None, this usually does not surprise people. For mutable values like lists, dictionaries, or sets, it can cause unexpected shared state.
Dangerous default values: lists, dictionaries, sets, or custom mutable objects.
Fixed Version
Use None as the default value, then create a new list inside the function.
def add_user(user, users=None):
if users is None:
users = []
users.append(user)
return users
print(add_user("Alice"))
print(add_user("Bob"))['Alice']
['Bob']Even Clearer Version
If the goal is to create a new list every time, avoid the optional list parameter entirely.
def create_user_list(user):
return [user]If the goal is to mutate an existing list, make that explicit.
def add_user_to_list(user, users):
users.append(user)
return usersHow To Explain This In An Interview
A strong review answer does not just say, “mutable default argument.” It explains the impact.
Common Interview Follow-Ups
Are all default arguments bad in Python?
No. Immutable defaults like None, strings, numbers, and booleans are usually fine. The problem is mutable defaults like lists, dictionaries, and sets.
Why use None instead of an empty list?
None is immutable and works as a sentinel value. It lets the function detect that no list was provided and create a fresh list for that call.
Is this ever intentionally used?
Sometimes advanced Python code uses mutable defaults for caching, but that is unusual and should be very explicit. In interview and production code, avoid it unless there is a clear reason.
What other mutable defaults should you watch for?
Dictionaries, sets, lists, bytearrays, and custom mutable objects can all cause the same shared-state problem.
Final Takeaway
[], , or set() as a default argument, stop and ask whether state might leak between calls.