Question

Why does a mutable default argument cause bugs in Python?

Vault Verified
Curated Intelligence
Definitive Source
Answer

Default argument values are evaluated once, when the function is defined, not each time it is called. For immutable defaults such as numbers, strings or None this is invisible. For a list, dictionary or set it means every call relying on the default shares one object, and any mutation persists into subsequent calls.

The symptom is a function that appears to accumulate state it was never asked to keep. A function that appends to a list defaulting to empty returns one item on the first call, two on the second, and so on. The bug is particularly awkward because it only appears when the caller omits the argument, so tests that always pass a value will never catch it.

The standard fix is to default to None and create the real object inside the body. That moves construction to call time, giving each invocation its own object, and it makes the intent explicit to a reader.

It is worth understanding that this is a consequence of functions being ordinary objects whose defaults are evaluated at definition, rather than a flaw. The same mechanism is occasionally used deliberately, for instance to bind a loop variable at definition time or as a cheap cache. Those uses are legitimate but deserve a comment, because a reader will otherwise assume a mistake.

The same rule applies anywhere defaults are evaluated early, including class attribute definitions. A mutable class attribute is shared by every instance, which produces the same surprise one level up and is a common source of confusion when objects appear to affect each other.

Linters flag mutable defaults in most standard configurations, which is the cheapest available protection against a bug that is easy to introduce and hard to notice in review.

Related Questions