unrust

Public code review lab

Why does this Python total work for a list but fail for a generator?

Published

Published by Unrust. Scoring and editorial method

Quick answer

The generator expression passed to any reads the underlying iterable. Because both quantities are non-negative, it reaches the end while looking for a true condition. A list can be traversed again, but a generator cannot be restarted by wrapping it in another expression. The repair validates and accumulates in one pass. It also avoids materializing an arbitrarily large input.

Read the contract before the patch

Accept a finite iterable of rows containing integer quantity values. Reject a negative quantity with ValueError and otherwise return the sum. A list and a one-shot generator containing the same rows must give the same result.

Predict the result before reading the repair. Use a small counterexample to separate the code’s behavior from the behavior you expected.

Original teaching example
def total_quantity(lines):
    if any(row["quantity"] < 0 for row in lines):
        raise ValueError("negative quantity")
    return sum(row["quantity"] for row in lines)

Compare the repair against the same inputs

The generator expression passed to any reads the underlying iterable. Because both quantities are non-negative, it reaches the end while looking for a true condition. A list can be traversed again, but a generator cannot be restarted by wrapping it in another expression. The repair validates and accumulates in one pass. It also avoids materializing an arbitrarily large input.

Repair under the stated contract
def total_quantity(lines):
    total = 0
    for row in lines:
        quantity = row["quantity"]
        if quantity < 0:
            raise ValueError("negative quantity")
        total += quantity
    return total
Execution-checked examples, 21 October 2026
InputOriginalRepair
List containing 2 and 577
Generator yielding 2 and 507
Empty generator00
Generator yielding 2 and -1ValueErrorValueError

Extend the review

The contract assumes finite input and integer quantities. This example does not validate row schemas, handle an infinite iterable or roll back external side effects.

Change one assumption, predict a new outcome, then run the example in your own environment. The public lab repository contains the snippets and their checks. These examples teach review reasoning; they do not measure coding ability.

Interactive reasoning check

Make your prediction

For a generator yielding quantities 2 and 5, what does the original function return?
Read the reasoning without answering

The generator expression passed to any reads the underlying iterable. Because both quantities are non-negative, it reaches the end while looking for a true condition. A list can be traversed again, but a generator cannot be restarted by wrapping it in another expression. The repair validates and accumulates in one pass. It also avoids materializing an arbitrarily large input.

A small practice loop

  1. 01State the input contract in your own words.
  2. 02Predict each boundary result before running the code.
  3. 03Compare the original and repair with exactly the same input.
  4. 04Write one additional case and explain what it establishes.

Common questions

Is this a scored Unrust assessment?

No. This is a fully public, worked teaching example. Its answers are intentionally available and it produces no diagnostic score.

Can I reuse the example in a tutorial?

Yes. The public lab source is MIT licensed. Keep the license, state the input contract and link to the example and its verification date.

Limits of this guide

The contract assumes finite input and integer quantities. This example does not validate row schemas, handle an infinite iterable or roll back external side effects.

Sources and scope

Original public teaching material authored for Unrust and execution-checked on 21 October 2026. It is separate from the diagnostic and Daily puzzle banks.

Check your own starting point

Unrust uses short, timed, unassisted drills to give developers a per-skill snapshot. One session cannot explain the cause of a result, but it can show you what is worth practicing next.

Take the free diagnostic