Default Mutable Arguments: The Classic Interview Trap
Why def f(lst=[]) causes shared state - and how to spot it in a trace.
AA
Ameer Abdullah
Data Science Graduate · AI/ML & Data Science
5 min read
Concept in Simple Words: In Python, default argument values are evaluated once, when the function is defined, not when it is called. If you use a mutable object (like a list or dictionary) as a default argument, all function calls that do not provide an argument will share the exact same object in memory.
Deep Walkthrough & Code: Let's look at the classic buggy implementation of a list accumulator:
def append_to(element, target=[]):
target.append(element)
return target
print(append_to(1))
print(append_to(2))Step-by-Step Dry Run: Let's trace this step-by-step: - At definition time: Python creates a default list object in memory, let's call it list_ref_1 = []. - First call: append_to(1) uses target = list_ref_1. We append 1. list_ref_1 becomes [1]. Returns [1]. - Second call: append_to(2) is called without target. It uses target = list_ref_1. We append 2. list_ref_1 becomes [1, 2]. Returns [1, 2]. This shared state leads to unexpected accumulation of values across independent function calls.
Production Level Issue & Fix: This is a major source of bugs in production APIs, where shared lists accumulate user data across requests. The fix is to use None as the default argument and instantiate the mutable object inside the function: `def append_to(element, target=None):
if target is None:
target = []
target.append(element)
return target`.Practice what you just learned
Apply these concepts in PyCodeIt's interactive sandbox with real problems.
Start Python Practice