Python DISCUSSION

Why does a list used as a default argument keep its values between calls in Python?

Started by reska mutable default argumentPython functionsdefault parametersNone sentinelshared state
4 replies 248 views 5 participants
Latest activity · 30 Sep 2026

Why does a list used as a default argument keep its values between calls in Python?

reska Python Forum
#1

I wrote a helper to collect ADC samples: def add_sample(value, samples=[]): samples.append(value); return samples. I expected every call without the second argument to start with a fresh empty list. Instead add_sample(1) returns [1], and the next call, add_sample(2), returns [1, 2].

Why is the list remembered between calls when it is only a parameter, and what is the recommended way to write a default that is an empty list or dictionary?

Community replies 4

Re: Why does a list used as a default argument keep its values between calls in Python?

#2

Default values are evaluated once, when the def statement runs, not each time the function is called. The resulting object is stored on the function object; you can see it as add_sample.__defaults__, which shows ([],) before the first call and ([1, 2],) after your two calls.

Every call that omits samples binds the parameter to that same list, and append mutates it in place. With immutable defaults such as 0, None, a string or a tuple the same sharing happens, but it is harmless because the object cannot change.

Re: Why does a list used as a default argument keep its values between calls in Python?

#3

The idiom is a None sentinel: def add_sample(value, samples=None): followed by if samples is None: samples = [] as the first line of the body. A new list is then created on every call that needs one.

Test with is None, not if not samples. The second form would also replace an empty list that the caller passed in deliberately and expects to be filled. If None is itself a meaningful argument, create a private marker, _MISSING = object(), use it as the default and compare with is.

Re: Why does a list used as a default argument keep its values between calls in Python?

#4

The same evaluate-once rule bites with other expressions. def log(msg, when=time.time()): freezes the timestamp at the moment the module is loaded, so every call reports the same time. def connect(port=find_port()): runs the search at import time, even if nobody ever calls connect.

Dataclasses guard against the list case: samples: list = [] inside a @dataclass raises ValueError when the class is created, and you write samples: list = field(default_factory=list) instead. A plain class attribute samples = [] has the same shared-object behaviour across all instances, so create per-instance containers in __init__.

Re: Why does a list used as a default argument keep its values between calls in Python?

#5

The behaviour is occasionally used on purpose as a cheap cache, def fib(n, _memo={0: 0, 1: 1}):, although functools.lru_cache says the same thing more clearly.

A related point: your function also modifies a list that the caller does pass. add_sample(3, my_list) changes my_list, because Python passes references to objects and append works in place. If the function should not touch the caller's data, copy first with samples = list(samples). Linters flag the original pattern: pylint reports it as dangerous-default-value (W0102) and flake8-bugbear as B006, so it is worth having one of them enabled.

TEP COMMUNITY