Python mutable default pitfall (or feature)
General mutable default issue
def buggy(items=[]): # Mutable default - DANGEROUS
items.append(1)
return items
print(buggy()) # [1]
print(buggy()) # [1, 1] - Unexpected!
# OUTPUT
# [1]
# [1, 1]
See this deep dive as well Common Gotchas — The Hitchhiker's Guide to Python (archived)
Problem
Classes decorated with dataclass reject mutable default values (lists, dicts, sets) with error:
field args is not allowed: use default_factory
Cause
Python evaluates default arguments once at definition time, not per-instance. Mutable defaults become shared across all instances, causing side-effect bugs.
Solution
Use field(default_factory=list) pattern:
from dataclasses import dataclass, field
@dataclass
class Example:
# WRONG: immutable_field: list = [] # Shared across instances!
# CORRECT: Creates new list per instance
mutable_field: list = field(default_factory=list)
dict_field: dict = field(default_factory=dict)
custom_obj: MyClass = field(default_factory=MyClass)
Implementation Note
default_factory accepts any callable that returns a new instance. For custom types, pass the class itself or a function that instantiates it.
Another example
From Python Cookbook book, page 223
```python
def spam(a, b=[]): ... print(b) ... return b
x = spam(1) x [] x.append(99) x.append('Yow!') x [99, 'Yow!'] spam(1) # Modified list gets returned! [99, 'Yow!']