Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Python function arguments: avoid shared mutable defaults

Last updated: 30 Sept 20264 min read
tutorial
BeginnerBy AITrove Editorial

Python evaluates a default argument when the function is defined, so a mutable default can be shared across later calls.

Download Python source kit

Operation contract

The receipt-tag function defaults to None and allocates a fresh list for that call. When a list is supplied, it copies it before appending so the caller retains its own collection. Those are two ownership decisions, not one syntax fix. The output proves both independent defaults and preservation of a supplied tag list.

Failure and ownership boundary

Using an empty list as the default can retain earlier callers’ tags. Using tags or [] would also treat a supplied empty list as though no object were supplied, which may be wrong when preserving identity is intentional. Python variables: names refer to objects, assignment does not copy explain why default allocation and caller-owned mutation need separate rules.

Working program

python
def receipt_tags(receipt_id, tags=None):
    owned_tags = [] if tags is None else list(tags)
    owned_tags.append(receipt_id)
    return owned_tags

shared_tags = ["reviewed"]
print(receipt_tags("R41"))
print(receipt_tags("R42"))
print(receipt_tags("R43", shared_tags))
print(shared_tags)

Output

Output
['R41']
['R42']
['reviewed', 'R43']
['reviewed']

Costs and limits

Copying t supplied tags takes O(t) time and storage; the default empty allocation is bounded. A shallow copy still shares mutable tag objects.

Common Mistakes

  • Do not put a mutable list in a reusable default.
  • Define whether the callee mutates or copies supplied state.

Connected lessons

Python variables: names refer to objects, assignment does not copy, Python functions: define units, validate input and return a result, Python closures: capture loop values at the intended time.

Apply this boundary

Python scope: local assignment, nonlocal state and late binding, Python unpacking: keyword collisions and strict record pairing.

Follow the related contract

Python input and output: separate parsing from terminal I/O.

Follow the service contract

Python positional-only and keyword-only parameters: keep call roles explicit.

python
function-arguments
Storage details