The request

From Thomas Whitaker, Head of Merchandising
Your goal
Fix apply_markdown so it returns a new list of prices reduced by pct percent (each rounded to 2) without changing the list it receives. Set result to a dictionary with two keys: 'list' (the original list_prices, unchanged) and 'sale' (the marked-down prices).
- Store a dict in
resultnot done yet
Your code
Loading the editor…
Reference solution
Mote checks your result
Press Run. Each row that matches the goal becomes a firefly in your lantern.
What Thomas gets, and why
The lesson
Two names, one list
When you call apply_markdown(list_prices, 20), Python does not copy the list. The parameter
prices becomes a second name for the same list object. Anything the function does to
prices[i] happens to list_prices too:
a = [369.00, 159.00]
b = a # no copy: two names for one list
b[0] = 295.20
a # [295.2, 159.0]
Numbers and strings can’t be changed in place, so this never bites with them. Lists and
dictionaries can, and that is where the surprise comes from. The starter’s loop with
range(len(prices)) walks positions 0 to 4 and writes each sale price back into the caller’s list,
which is why the “list” and “sale” columns came out identical. Nothing raised an error; the damage
only showed up in the numbers.
Return a new list instead
The safe pattern is a function that reads its input and builds a fresh output. A list comprehension does that in one line:
def apply_markdown(prices, pct):
return [round(p * (1 - pct / 100), 2) for p in prices]
After the fix, list_prices still holds 369.00, 159.00, 72.99, 27.99 and 44.99, and the sale
prices are 295.20, 127.20, 58.39, 22.39 and 35.99. You can run the function again with 25% and get
a correct second answer, because nothing was overwritten the first time.
If you really need a loop, copy first with prices = list(prices) at the top of the function, then
edit the copy. Writing a new list is usually simpler.
How to spot this kind of bug
The symptom is always the same: data you didn’t touch changes after a function call. Two quick
checks find it. Print the input before and after the call, and look inside the function for
assignments into an argument (prices[i] = ..., row["x"] = ...) or methods that change it
in place, such as .append(), .sort() or .pop().
Common mistakes
- Returning
prices.copy()at the end. The original was already changed by the loop. - Writing
sale_prices = list_pricesbefore the call and thinking it is a copy. It is a second name. - Using
list_prices.sort()inside a report function, which reorders the caller’s list for good.
Lantern lit!
Practised: debuggingfunctionsmutabilitylistsrange
- Solved
- No hints
- First run
