Backend / Python core / Tricky questions / 01_mutable_default_arguments.md

Mutable default arguments

Updated 1 min read source
On this page5
  1. The gotcha
  2. Minimal repro
  3. Why it happens
  4. How to avoid
  5. Interview angle

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

python
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.

python
print(append_to.__defaults__)  # ([1, 2, 3],)

How to avoid

Use None as the sentinel and create the mutable object inside:

python
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.