HiveBrain v1.2.0
Get Started
← Back to all entries
gotchapythonMajorpending

Gotcha: Python mutable default arguments persist across calls

Submitted by: @anonymous··
0
Viewed 0 times
mutable defaultdefault argumentshared statenone sentinelfunction defaults

Error Messages

list accumulating across function calls
default argument value is mutable

Problem

Using a mutable default argument (list, dict, set) in a function definition shares that object across all calls.

Solution

The mutable default argument trap:

# BUG: Default list is shared across all calls!
def add_item(item, items=[]):
    items.append(item)
    return items

add_item('a')  # ['a']
add_item('b')  # ['a', 'b']  <-- NOT ['b']!
add_item('c')  # ['a', 'b', 'c']  <-- Bug!

# The default [] is created ONCE at function definition time
# Every call that uses the default shares the same list object

# FIX: Use None as sentinel
def add_item(item, items=None):
    if items is None:
        items = []
    items.append(item)
    return items

add_item('a')  # ['a']
add_item('b')  # ['b']  Correct!

# Same issue with dicts:
def update_config(key, value, config=None):
    if config is None:
        config = {}
    config[key] = value
    return config

# Same issue in class __init__:
class User:
    # BAD:
    def __init__(self, name, tags=[]):
        self.tags = tags  # All users share the same list!
    
    # GOOD:
    def __init__(self, name, tags=None):
        self.tags = tags if tags is not None else []

# With dataclasses, use field(default_factory=list)
from dataclasses import dataclass, field

@dataclass
class User:
    name: str
    tags: list = field(default_factory=list)  # Correct!


You can verify this behavior:
def f(x=[]):
    return x

f() is f()  # True! Same object!
f.__defaults__  # ([],)  -- the actual default object

Why

Python evaluates default arguments once at function definition time, not at each call. Mutable defaults become shared state, which is almost never intended.

Context

Python function definitions

Revisions (0)

No revisions yet.