1. Lighthouse

Level 2 · Return an order summary

The request

From Jennifer Castillo, Support Team Lead

“When a customer disputes a charge, I need three numbers fast: how many items, the total, and the average item price. Could one function give me all three?”

Your goal

Define order_summary(prices) returning a dict with keys 'items' (count of prices, int), 'total' (sum, rounded to 2) and 'average' (total divided by count, rounded to 2; use 0.0 when the list is empty). Set result to order_summary([49.99, 34.00, 34.00, 12.50]).

  • Store a dict in resultnot done yet

Your code

Python

Loading the editor…

    ResultPress Run to see yours

    Mote checks your result

    Press Run. Each row that matches the goal becomes a firefly in your lantern.

    The lesson

    One function, several answers

    A function returns one object, but that object can hold several values. Two common choices are a tuple and a dictionary.

    A tuple is quick:

    def min_max(prices):
        return min(prices), max(prices)
    
    low, high = min_max([49.99, 34.00, 12.50])   # unpack into two variables

    A dictionary is clearer when there are more than two values, because each value has a name:

    summary = order_summary([49.99, 34.00, 34.00, 12.50])
    summary["total"]      # 130.49
    summary["average"]    # 32.62

    Nobody has to remember that the total is “the second thing”. In analysis code that gets shared, named results win.

    Building the summary

    Compute the pieces into well-named variables, then assemble the dictionary at the end:

    def order_summary(prices):
        count = len(prices)
        total = sum(prices)
        average = total / count if count else 0.0
        return {"items": count, "total": round(total, 2), "average": round(average, 2)}

    Rounding happens only in the returned values. The average is computed from the unrounded total, so no rounding error creeps into it.

    The conditional expression

    total / count if count else 0.0 is an inline if: value-if-true, if condition, else value-if-false. It’s ideal for small choices like this. An empty list has count == 0, and 0 counts as false in a condition, so the function returns 0.0 instead of crashing.

    That works because every value in Python is “truthy” or “falsy”. Falsy values are 0, 0.0, "", [], {}, None and False; almost everything else is truthy. if prices: is the idiomatic way to ask “is this list non-empty?”.

    Edge cases are part of the job

    Without the guard, order_summary([]) raises ZeroDivisionError: division by zero. Will an empty cart ever reach this function? In production data, the answer is almost always “yes, eventually”. Think about the empty case, the single-item case, and odd values (zero or negative prices) for every function you write, and decide what it should do.

    Whether “0.0” or “no average” (None) is the right answer for an empty cart is a design decision. Here the brief says 0.0, so that’s what the function returns.

    Testing a function

    Call it on cases where you know the answer:

    order_summary([10, 20])     # {'items': 2, 'total': 30, 'average': 15.0}
    order_summary([])           # {'items': 0, 'total': 0, 'average': 0.0}

    A couple of hand-checked calls catch most mistakes, such as dividing by the wrong count or returning the total under the wrong key.

    Common mistakes

    • Using round() on the total before computing the average.
    • Misspelling a key, for example "avg" instead of "average". The checker, and your colleagues, look for the exact name.
    • Forgetting the empty-list guard and letting ZeroDivisionError reach the user.