---
title: Do Not Use Mutable Default Argument
impact: HIGH
impactDescription: Mutable default arguments are shared across all calls, causing subtle state bugs that are very hard to trace.
tags: python, bugs, arguments, pitfalls, quality
---

## Do Not Use Mutable Default Argument

In Python, default argument values are evaluated **once** at function definition time, not at each call. Using mutable objects (list, dict, set) as defaults causes all callers to share the same object, leading to unexpected side effects across calls.

**Incorrect:**
```python
def add_item(item, collection=[]):
    collection.append(item)
    return collection

print(add_item("a"))  # ["a"]
print(add_item("b"))  # ["a", "b"]  ← bug: list persists between calls

def create_user(name, roles={"admin": False}):
    roles["user"] = True
    return {"name": name, "roles": roles}
```

**Correct:**
```python
def add_item(item, collection=None):
    if collection is None:
        collection = []
    collection.append(item)
    return collection

print(add_item("a"))  # ["a"]
print(add_item("b"))  # ["b"]  ← each call gets a fresh list

def create_user(name, roles=None):
    if roles is None:
        roles = {"admin": False}
    roles["user"] = True
    return {"name": name, "roles": roles}
```

**Dataclass alternative (Python 3.7+):**
```python
from dataclasses import dataclass, field
from typing import List

@dataclass
class Task:
    name: str
    tags: List[str] = field(default_factory=list)  # safe: fresh list per instance
```

**Tools:** Ruff `B006` (mutable-argument-default), Pylint `W0102` (dangerous-default-value), flake8-bugbear, mypy
