ILTS Computer Science (205) study materials
ILTS Computer Science (205) study resources

The Cart That Remembered the Last Student

ILTS Computer Science (205) · Put your knowledge to work in context.

All case studies

The Cart That Remembered the Last Student

Mr. Bhatt's introductory Python students build a book-cart module. Priya submits a solution whose central functions are defined as def add_item(item, cart=[]) and def cart_total(cart=[]). She tested each function in IDLE by running one file at a time and saw every check pass. The class autograder collects all tests into a single pytest process in alphabetical order, so test_add_one, test_add_two, and test_shared_cart run back to back against the same interpreter. In that run the cart length grows 1, then 3, then 6 instead of 1, 2, 2, and Priya loses 8 of 40 points, all from the cart section. Her message reads: My code works. The grader is running my tests in a weird order and keeping state. This is unfair. The published rubric awards 32 points for all tests passing, 4 for PEP 8 style, and 4 for a README, with no category for design rationale or robustness. Two other students in the same class hit the identical failure.

1. Explain to Priya what is actually happening and state whether her grade should change. Justify both parts.

Read the worked answer

Default argument values are evaluated once, when the def statement executes, not on each call. The expression cart=[] therefore creates a single list object shared by every call that omits the argument, and it lives as long as the function object does. In IDLE, when Priya ran one file and then stopped, the interpreter exited and the list was destroyed, so each run started clean. Under pytest, all three test modules are imported into one process; whichever test runs first mutates the shared list and the next test inherits the mutation. The failure is produced by her design choice, not by test order. Any caller who calls add_item twice without passing a cart would see the same corruption, which is precisely what test_shared_cart exists to catch. So the test result is accurate and the eight points stand as the correctness score. What is not defensible is the process: the class taught a testing habit, run the file, that cannot expose this class of defect, then placed 80 percent of the grade on a single all-or-nothing gate. The fair remedy is a documented redo, not a retroactive curve.

2. Redesign the task and its rubric so that this failure is caught by students, not only by the autograder.

Read the worked answer

Three changes. First, make the harness public and identical to the grader: ship a pytest file that students run with one command before submitting, and require a commit or screenshot showing all tests passing in a single run. Debugging under a runner is a course objective, not an ambush. Second, change the function contract so the trap is visible: require def add_item(item, cart=None) with an explicit if cart is None branch, or better, a Cart class whose init creates per-instance state. The class version teaches object state and encapsulation, and the original bug turns into a design conversation rather than a gotcha. Third, rebalance the rubric: 40 percent public test suite, 20 percent hidden edge cases such as two calls with no arguments, an empty cart, and duplicate items, 20 percent a short design note answering what would happen if two students shared my cart and why, 10 percent peer code review, 10 percent style. With that structure a single conceptual error costs a strand rather than the assignment, and the written strands reveal whether Priya can now explain the mechanism.

3. A third of the class made the same error. What does that imply about the unit, and what would you change for the next cohort?

Read the worked answer

When three students independently make the same error, the likely cause is the curriculum rather than the students: the concept was probably never taught. Mutable default arguments are a Python-specific trap that follows from the semantics of function objects, and a typical introduction to functions never surfaces those semantics. Treat it as a named objective. Demonstrate it live with two calls in one interpreter session: have students predict the output of a function with an accumulator default, run it, then draw the function object and its defaults tuple to show where the list lives. Pair it with aliasing (b = a, copy, shallow versus deep), since one mental model explains both. Build the full suite into every assignment from the second week so running everything at once becomes habitual. Finally, add the item and its rubric language to the department item bank so the next teacher's class does not meet the same failure as a surprise, and note in the unit plan that the misconception clusters with aliasing and shared state rather than with syntax.