Why Mutable Default Arguments persist data across function calls.
Timothy stared at the glowing terminal, shaking his head.
"I can’t trust it," he whispered. "I just can’t trust the data."
Margaret looked up from her desk. She set down her pen and walked over to stand beside him. "What is it, Timothy?"
"It’s this security logger," Timothy said, his voice tight with frustration. "I wrote a function to track alerts. It’s supposed to start fresh every time I call it. But it’s not. It’s remembering things it shouldn’t. It’s mixing data from different shifts, and I can’t find the leak."
He pointed to the code, looking defeated.
# Timothy's Function
def add_alert(message, history=[]):
history.append(message)
return history
# Call 1: Morning Shift
print("Morning:", add_alert("Server Reboot"))
# Call 2: Evening Shift
print("Evening:", add_alert("User Login"))
"Look," Timothy said, pointing at the output. "In the second call, I didn’t provide a history list. So it should default to a new, empty list. But look what it printed."
Morning: ['Server Reboot']
Evening: ['Server Reboot', 'User Login']
"The ‘Server Reboot’ from the morning is showing up in the evening log," Timothy said, throwing his hands up. "Why is the second call stealing data from the first call?"
The Shared Object
Margaret pulled a chair over and sat next to him. "You are using a mutable object as a default argument," she said gently. "In Python, default arguments are not created fresh every time you run the function; they are created exactly once and shared across every single call."
She stood up and moved to the whiteboard. She drew a timeline.
1. Definition Time (When Python reads the code)
def add_alert(message, history=[]):
"Right here," Margaret said, pointing to the line. "When Python reads this def statement, it creates that list []. It creates it one time. It stores that specific list object in memory and attaches it to the function definition."
2. Runtime (When you call the function)
add_alert("Server Reboot")
"When you call the function," she continued, "you didn’t provide a list. So Python grabs that stored list—the one it made earlier. You append ‘Server Reboot’ to it."
3. Runtime (The second call)
add_alert("User Login")
"Now, you call it again," Margaret said. "You didn’t provide a list. So Python grabs the exact same stored list. It still has ‘Server Reboot’ inside it from the last time. You aren’t getting a new empty list; you are getting the same list you modified five minutes ago."
Timothy stared at the board. "So the [] isn’t an instruction to make a list? It is the list?"
"Exactly," Margaret said. "And because it is a list, it is mutable—it can be changed. If you change it, it stays changed."
The Runtime Fix
"So how do I make it create a new one every time?" Timothy asked.