Mutable Default Arguments in Python
Explaining a common pitfall when using Python's default function arguments.
September 2, 2025 · min read
Recently, I made a beginner mistake when it comes to using mutable data structures (lists, dictionaries, etc.) in default arguments.
Take this code snippet as an example:
from typing import List
def func(a: List[str] = []) -> List[str]:
return a
arr1 = func() # arr1 = []
arr2 = func() # arr2 = []
arr1.append('a')
print(f'arr1: {arr1}')
print(f'arr2: {arr2}')
Output:
arr1: ['a']
arr2: ['a']
Why did mutating arr1 affect arr2? Shouldn't they be different list instances?
Why?
Looking at the Python docs at 8.7. Function definitions, it states: the expression is evaluated once, when the function is defined, and that the same “pre-computed” value is used for each call.
This behaviour works with primitive types, but unexpected errors occur when using mutable objects, since the same object instance is used for every function call, instead of a new instance being created.
Thus, the output is attributed to arr1 and arr2 sharing the same list instance.
The Fix
To use mutable objects as default arguments in Python, we can use the primitive None as the default value, then explicitly test for it:
from typing import Optional, List
def func(a: Optional[List[str]] = None) -> List[str]:
if a is None:
return []
return a
arr1 = func() # arr1 = []
arr2 = func() # arr2 = []
arr1.append('a')
print(f'arr1: {arr1}')
print(f'arr2: {arr2}')
Output:
arr1: ['a']
arr2: []
The pattern above, ensures that a new object instance is created every time the function is called.
And if there's one thing to remember, it is to prevent using mutable data types directly as default arguments.
References
- 8. Compound Statements - Python 3.10 Documentation
- Python Mutable Object as Default Argument - Lei Mao's Log Book