Why does a mutable default argument cause bugs in Python?
Short answer
A default argument is created once when the function is defined, not on each call, so a mutable default like a list is shared across calls and accumulates changes. Use None as the default and build the object inside.
The short version
Default argument values are evaluated once, when the function is defined, not each time it is called. So a mutable default such as a list or dictionary is created a single time and shared by every call, quietly accumulating changes. The fix is to default to None and create a fresh object inside the function.
Seeing the bug
def add_item(item, bucket=[]):
bucket.append(item)
return bucket
print(add_item("a")) # ['a']
print(add_item("b")) # ['a', 'b'] <- the surprise
The second call did not start with an empty list. Both calls used the same list object, the one created when the function was defined, so the "a" from the first call is still there.
Why this happens
When Python runs the def line, it evaluates the default [] once and stores that exact list on the function. Every call that does not supply bucket reuses that stored list. Because lists are mutable, append changes it in place, and the change persists to the next call. The default is not re-created per call, which is the mental model most people wrongly assume.
The fix
Default to None, then create the real object inside the body. Now each call that omits the argument gets a brand-new list.
def add_item(item, bucket=None):
if bucket is None:
bucket = []
bucket.append(item)
return bucket
print(add_item("a")) # ['a']
print(add_item("b")) # ['b']
Why None specifically
None is immutable and unambiguous, so it is the conventional sentinel for "no value supplied". You check if bucket is None rather than if not bucket, because an empty list is also falsy and you might legitimately want to allow one.
Immutable defaults are safe
The trap only applies to mutable defaults. Numbers, strings, tuples and None cannot be changed in place, so sharing them across calls is harmless.
def greet(name, greeting="Hello"): # fine, strings are immutable
return f"{greeting}, {name}"
The rule
Never use a list, dictionary, set or other mutable object as a default value. Default to None and build it inside. Some linters flag this automatically, which is worth enabling.