September 11, 2026
Why Is My Python List Changing When I Didn't Touch It?
If you've ever written a function with a list as a default argument and watched it mysteriously grow across unrelated calls, you've hit one of Python's most common gotchas — and it's not a bug in Python, it's how default arguments actually work.
def add_item(item, items=[]):
items.append(item)
return items
print(add_item("apple"))
print(add_item("banana"))['apple'] ['apple', 'banana']
The second call, add_item("banana"), returns ['apple', 'banana'] — not ['banana'] like you'd probably expect. Nothing about the second call mentions the first one, so what's actually happening?
Default arguments are evaluated once, not per call
Python evaluates a function's default argument values exactly once, when the function is defined — not each time the function runs. def add_item(item, items=[]) creates ONE list object at definition time, and every call that doesn't pass its own items argument shares that exact same list. append() then mutates that shared object on every call.
The fix: use None as the default, and create the list inside
def add_item(item, items=None):
if items is None:
items = []
items.append(item)
return items
print(add_item("apple"))
print(add_item("banana"))['apple'] ['banana']
Now items=None is the default (an immutable value, safe to reuse), and a fresh, empty list is only created inside the function body when the caller didn't supply their own. Each call that relies on the default now gets its own independent list.
This exact pattern — mutable default arguments — applies to dictionaries and sets too, not just lists. For a closer look at how Python handles arguments and parameters, see the Functions lesson in our free Python course.