Default argument objects are evaluated when the function is defined, not freshly on each call. Mutable defaults can therefore share state across calls.
Before you start
You should know Python functions, collections and exceptions. Use a small isolated script or interactive session to trace the example. Pay attention to when objects are created and when work executes; iteration, binding and mutation can happen at different points in a program.
The practical goal is to reason through this situation: A function appending to a default list retains earlier items. Read the walkthrough first, then try the interview exercise before opening its answer. The important part is explaining the decision and its consequences, rather than remembering a definition alone.
Step-by-step walkthrough
Step 1: Locate object creation
Default argument objects are created when the function definition executes.
Step 2: Trace consecutive calls
Appending during one call changes the list reused by the next call.
Step 3: Create per-call state
Use None as a sentinel and allocate inside the function when omitted.
Worked scenario
A function appending to a default list retains earlier items.
def append_item(item, items=None):
if items is None:
items = []
items.append(item)
return items
print(append_item('a')) # ['a']
print(append_item('b')) # ['b']A supplied list is still modified intentionally; independent omitted arguments do not share state.
Common mistake
Assuming every call receives a new list produces cross-request contamination.
Verify the behavior
Test omitted input twice and an explicitly supplied empty list; distinguish intended caller mutation from accidental sharing.
Interview exercise
Create an independent optional list.
Answer and reasoning
Default to None and create a new list inside the function when no list is supplied.
Continue learning
Compare the scenario with the Python interview questions and test your understanding with the Python MCQs. For terminology and implementation details, consult the reference material.