Mutable default arguments
The gotcha
Default argument values are evaluated once, at function definition time, and the same object is reused across calls.
Minimal repro
def append_to(item, target=[]):
target.append(item)
return target
print(append_to(1)) # [1]
print(append_to(2)) # [1, 2] ← surprise: same list reused
print(append_to(3)) # [1, 2, 3]
Why it happens
When Python compiles def, it evaluates [] once and stores the resulting list object in func.__defaults__. Every call that omits target binds the parameter to that same shared object. Mutating it via append mutates the default itself.
print(append_to.__defaults__) # ([1, 2, 3],)
How to avoid
Use None as the sentinel and create the mutable object inside:
def append_to(item, target=None):
if target is None:
target = []
target.append(item)
return target
For dataclasses, use field(default_factory=list) — same problem in a different shape (see 18_dataclass_mutable_default.md).
Interview angle
Asked to spot the bug, predict output, or fix it. Sometimes hidden inside a longer snippet using def f(x, cache={}) for memoization — which actually works as a cheap memoization trick, but is fragile. Prefer functools.lru_cache.