Skip to content
LakeBench
ProblemsCommunityPricing
Sign inStart practicing
Back
  1. Home
  2. Interview prep
  3. Mutable default arguments

Python · Language Internals Interviewers Still Ask

Mutable default arguments

Easypython-62
functionsmutable-defaultsgotchasnone-sentinel

Question

What is wrong with `def add(item, items=[])`?

Solution

The default value [] is created once, when the function is defined, not each time it is called. So every call that uses the default shares the same list, and items from earlier calls stay in it.

Seeing the bug

def add(item, items=[]):
    items.append(item)
    return items

add("a")    # ['a']
add("b")    # ['a', 'b']   <- the list from the first call is still there
add("c")    # ['a', 'b', 'c']

Each call looks independent, but they all use the same list object that Python created when it read the def line. You can see it: add.__defaults__ shows the list growing.

The fix: use None as a marker

def add(item, items=None):
    if items is None:
        items = []
    items.append(item)
    return items

A new list is created inside the function on each call. Use is None and not if not items, because an empty list passed by the caller is falsy, and you would replace it by accident.

The same bug with other mutable types

Dictionaries, sets and any mutable object used as a default behave the same way. In pipeline code it often appears like this:

def run_job(name, config={}):        # one shared dict for every job
    config["name"] = name            # leaks into the next call

Two jobs run in the same process would share and overwrite each other's settings, a hard bug to find because it depends on call order.

Where defaults are fine

Immutable defaults such as numbers, strings, tuples, None and True cannot be changed in place, so sharing them is harmless.

A deliberate use

Some people use a mutable default as a cheap cache on purpose. It works, but it is obscure. Use functools.lru_cache or an explicit module-level dictionary so the intent is clear.

What interviewers want

They ask it to see whether you know that defaults are evaluated at definition time, and that you can name the None pattern. Linters (flake8-bugbear, ruff) flag it automatically, so mention that you would let tooling catch it.

🎯 Put this concept into practice

Solidify this answer with real hands-on interview drills in the browser studio.

Open related drill →
PreviousNext