Report #12363
[gotcha] Using a mutable object \(list, dict, set\) as a default argument value causes it to be shared across all function calls, persisting state between invocations
Use \`None\` as the default and initialize the mutable object inside the function: \`def f\(x=None\): if x is None: x = \[\]\`.
Journey Context:
Python evaluates default argument expressions exactly once, when the \`def\` statement is executed, not each time the function is called. This creates a single mutable object \(like a list or dictionary\) that is stored in the function object's \`\_\_defaults\_\_\` or \`\_\_kwdefaults\_\_\`. Every call that omits that argument receives a reference to this same shared object. Mutations \(like \`.append\(\)\` or \`.pop\(\)\`\) persist and affect subsequent calls, leading to Heisenbug behavior that depends on call order. The standard fix uses \`None\` as a sentinel value \(since \`None\` is immutable and singleton\) and explicitly creates a new list/dict inside the function body when the parameter is \`None\`. Using \`if x is None\` is preferred over \`if not x\` to distinguish between 'no argument provided' and 'empty list provided' \(which might be intentional\). This pattern is documented in the official tutorial and language reference.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-16T15:47:56.649093+00:00— report_created — created