Why L=[] as a Python default argument keeps growing: defaults are built once, at def time

Call def f(a, L=[]) three times and the list keeps growing. What the Python docs say about when defaults are evaluated, __defaults__, the None pattern and dataclass default_factory.

DevelopmentPython

What does this print?

def f(a, L=[]):
    L.append(a)
    return L

print(f(1))
print(f(2))
print(f(3))

If each call got a fresh list, you would see [1], [2], [3]. It actually prints [1], [1, 2], [1, 2, 3]. The official Python tutorial carries this exact example under an “Important warning” heading. It is defined behaviour, not a bug.

This article follows the Python 3.15.0 documentation as checked on 10 October 2026. The evaluation rule for defaults described here is the same throughout Python 3. The one version-dependent detail is in the dataclass section.

Defaults are evaluated when the def statement runs

The function definitions section of the language reference says that default parameter values are evaluated from left to right when the function definition is executed, and that the same pre-computed value is used for each call.

def is a statement that executes, not a declaration. When a module is imported, or a script reaches that line, Python builds the function object, evaluates the expressions to the right of each =, and attaches the results to the function. A call does not evaluate those expressions again; it binds the stored object to the parameter.

So there is exactly one empty list behind L=[] per function. Every call that omits the argument receives that list, and whatever append added is still there on the next call.

Another tutorial example shows the same rule:

i = 5

def f(arg=i):
    print(arg)

i = 6
f()   # 5

i was 5 when the def ran, so the default is 5. Rebinding i to 6 afterwards does not touch it.

Looking at the function object

The computed defaults live on the function object as a tuple in __defaults__. The data model documentation describes it as a tuple containing default values for the parameters that have defaults, or None if none do. Defaults for keyword-only parameters are kept separately in the __kwdefaults__ dictionary.

After the three calls to f(a, L=[]) above, f.__defaults__ would hold ([1, 2, 3],). That is where the default “remembers” things between calls. If a function seems to carry hidden state while you debug, printing this attribute is the quickest check.

Which defaults cause trouble

Sharing the default is not a problem in itself. The trouble starts when the function changes the shared object. The FAQ notes that immutable objects such as numbers, strings, tuples and None cannot be changed and are safe, while mutable ones such as dictionaries, lists and class instances lead to confusion. The tutorial’s warning names lists, dictionaries and “instances of most classes”.

The forms you are likely to meet:

  • A function like def add(item, items=[]) that calls append or update on the collection it receives.
  • A constructor def __init__(self, tags=[]) that stores self.tags = tags. Every instance created without that argument shares one list.
  • A function like def log(msg, when=datetime.now()) that wants the call time as its default. The time is computed once, when the def runs, so every later call records the same moment.

The last case is about when the expression runs rather than about mutability. Both come from the same rule: a default expression runs once, at definition time.

Take None and build the object inside

The reference, the tutorial and the FAQ all recommend the same fix. Use None as the default, test for it in the body, and create the new object there.

def f(a, L=None):
    if L is None:
        L = []
    L.append(a)
    return L

Now [] runs on every call, so each call that omits the argument gets its own list. The timestamp case works the same way: accept when=None and call datetime.now() in the body.

Write the test as if L is None. Some code shortens it to L = L or [], but that replaces every falsy value, not only None. If a caller passes an empty list in order to collect results, the function appends to a new list instead, and the caller’s list stays empty.

When None is itself a meaningful argument and you need to tell it apart from “not passed”, create a dedicated object at module level, such as _MISSING = object(), use it as the default and compare with is. Nothing else can produce that object, so a caller cannot pass it by accident.

Sharing on purpose

The FAQ adds that the behaviour can be useful, and gives a memoization example that remembers results of an expensive function:

def expensive(arg1, arg2, *, _cache={}):
    if (arg1, arg2) in _cache:
        return _cache[(arg1, arg2)]
    result = ...  # expensive computation
    _cache[(arg1, arg2)] = result
    return result

Placing _cache after * makes it keyword-only, and the leading underscore marks it as internal. The FAQ says a global variable holding a dictionary would work too and calls it a matter of taste. To a reader who does not know the intent, this looks exactly like the bug above, so leave a comment if you do it. If memoization is the goal, the standard library also has the functools.cache (since 3.9) and functools.lru_cache decorators.

dataclass blocks part of the problem

In a @dataclass, a field’s default becomes a default argument of the generated __init__, so the same sharing can happen. According to the dataclasses documentation, the decorator raises ValueError when it finds an unhashable default, on the assumption that an unhashable value is mutable.

from dataclasses import dataclass, field

@dataclass
class D:
    x: list = []                          # ValueError

@dataclass
class D:
    x: list = field(default_factory=list) # a new list per instance

This check changed in Python 3.11. Up to 3.10 it rejected only objects of type list, dict and set; from 3.11 it rejects any unhashable object. The documentation itself calls this a partial solution. A mutable object that is hashable gets through, so when a field needs a mutable default, passing a zero-argument callable to default_factory is the reliable route.

Plain functions and classes get no such check. def f(L=[]) is defined without any warning, so it has to be caught in code review or by a linter.

Summary

  • A default expression is evaluated once, when the def runs, and that object is reused by every call.
  • If the function changes the default object, the change carries over to the next call. Lists, dictionaries and most class instances are affected.
  • Default to None and build a new object in the body with if x is None:.
  • In a dataclass, use field(default_factory=...).

References

Checked on 10 October 2026 (Python 3.15.0 documentation)

Back to the blog