What does this print, and why?
def add(item, bucket=[]):
bucket.append(item)
return bucket
print(add(1))
print(add(2))How do you fix it?
Show the explanation
Output
[1]
[1, 2]Why. Default values are evaluated once, when the def statement runs, not on every call. The empty list is created a single time and stored on the function object (you can see it in add.__defaults__). Every call that does not pass bucket gets the same list object, so it keeps growing.
The fix: use `None` as a sentinel
def add(item, bucket=None):
if bucket is None:
bucket = [] # a new list on every call
bucket.append(item)
return bucketUse is None rather than if not bucket. An empty list that the caller passes on purpose is falsy, and you do not want to replace it.
The idea underneath: names are references. Python variables are names bound to objects. Assignment never copies:
a = [1, 2]; b = a; b.append(3) # a is now [1, 2, 3]- Mutable objects (list, dict, set, most user classes) can change in place, and every name bound to them sees the change.
- Immutable objects (int, float, str, tuple, frozenset) cannot change. "Modifying" one creates a new object.
The same trap appears with [[0] * 3] * 3. It creates three references to one inner list, so setting grid[0][0] = 1 changes every row. Use [[0] * 3 for _ in range(3)] instead.
Linters (pylint, ruff) flag mutable default arguments. The behaviour is occasionally used on purpose as a simple cache, but functools.lru_cache is clearer.
Original UniCircle question. Last reviewed 22 Oct 2026.
