You ask an AI assistant for a small Python helper that collects an item into a list. The first demonstration returns exactly what you expect. The second job includes the first job’s item as well. Nothing has been read from a database, and nobody deliberately asked for a shared collection.
The function’s default argument can explain the result. A default list is not necessarily a fresh list for every call. For creators and small business owners using AI-assisted scripts, that detail matters whenever separate batches, exports or customer jobs are meant to remain separate.
A small function exposes the problem
Consider this deliberately faulty helper. It accepts an item and an optional list, appends the item and returns the list:
def add_item(item, items=[]):
items.append(item)
return items
The default looks inviting: leave out the second argument and start with an empty collection. However, Python’s official tutorial explains that default values are evaluated when the function is defined. A mutable default, such as a list, can therefore accumulate changes across subsequent calls that use it.
The name items is local to a call, but in this example its value refers to the same default list on successive calls. Writing the parameter inside a function signature does not promise a newly created container whenever the function runs.
Run two jobs without redefining the helper
For this article, the following sequence was checked locally using Python 3.12.14 and fictional colour labels:
first = add_item('TEAL')
second = add_item('GOLD')
Immediately after the first call, the returned list contains only 'TEAL'. After the second call, second contains ['TEAL', 'GOLD']. The earlier variable first now shows that same two-item list. The identity check first is second returns True.
That last observation is especially useful in review. The helper has not merely copied an earlier value into a later result; both returned references lead to the same changing object. Inspecting the first result only before the second call would miss its later change.
These checks establish the behaviour of this small example. They do not establish that a particular live customer system has mixed records. If a production workflow shows similar symptoms, inspect its actual call path and state before assigning a cause.
Create the list inside the call that needs it
When the intended contract is “make a new list if none is supplied”, the tutorial’s pattern uses None as the default and creates the container inside the function body:
def add_item_fresh(item, items=None):
if items is None:
items = []
items.append(item)
return items
In the local check, add_item_fresh('TEAL') returns ['TEAL'] and the subsequent add_item_fresh('GOLD') returns ['GOLD']. Retaining both results confirms that the first remains unchanged, and their identity comparison is False.
The creation step now runs during each call that receives None. This is a focused correction to the helper’s behaviour. It does not validate item types, enforce a business rule about permitted colours or make an entire batch-processing application ready for use.
Decide what supplying a list should mean
The corrected helper still appends to a list deliberately supplied by the caller. That is part of this example’s chosen contract, and it deserves a separate check:
provided = []
result = add_item_fresh('PURPLE', provided)
In the tested sequence, provided becomes ['PURPLE'] and result is provided is True. An explicitly supplied empty list is still the caller’s list; the correction does not replace it.
A different commission might require the helper to leave every supplied list untouched and return a separate collection. That would require a different implementation and corresponding tests. State the intended behaviour before asking an assistant to shorten or refactor the code.
Also distinguish this issue from nested copying. MaryChuks.com’s guide to copied lists and shared records examines why a new outer list can still contain references to existing inner objects. Creating a fresh default container addresses a different boundary.
Turn the symptom into a useful AI review request
Imagine a fictional studio building separate lists of assets for two client deliveries. Rather than asking an assistant simply to “fix the list bug”, the owner could specify the acceptance conditions:
- Two consecutive calls that omit the list must receive separate collections.
- Keeping the first result must not allow a later independent call to change it.
- Supplying an existing list must follow the agreed mutation or copying rule.
- An explicitly supplied empty list must receive the same treatment as any other supplied list.
- The demonstration must run consecutive calls against the same function definition.
Ask the assistant to explain which line creates the list and when that line executes. Then run the relevant checks. A prose explanation can help a reviewer understand the proposal, but the observed results should agree with the promised contract.
For a real studio, extend the checks to the actual asset records and the stage that writes the delivery file. A corrected helper is useful only if the surrounding workflow calls the intended version and passes the intended data.
Separate intentional memory from accidental carry-over
Python’s Programming FAQ recommends avoiding mutable defaults for ordinary use and describes the None pattern. It also explains that retained state can be intentional, illustrating a cache that remembers earlier results.
That distinction prevents an overbroad rule. A function designed to maintain shared state needs a clear purpose and lifetime. A function preparing independent deliveries needs separation. The review question is whether the implemented lifetime matches the business requirement.
For this example, the retained list belongs to the function object used in the repeated calls. The demonstration does not show durable storage across separate programme executions or an AI model remembering information. Keep the explanation at the layer where the state actually lives.
A single successful call is a useful beginning. For an independent-job workflow, the next call provides the decisive check: does it start with the collection the specification promised, and does the earlier result remain intact?
Sources
- Python 3.12 tutorial: Default Argument Values.
- Python 3.12 Programming FAQ: Why are default values shared between objects?.
Documentation checked on 5 November 2026. The small function examples were tested using Python 3.12.14; the studio scenario is fictional.
Discover more from Marychuks.com AI, Psychology, Business & CreativeVerse
Subscribe to get the latest posts sent to your email.