The request

From Angela Rivera, Head of Customer Support
Your goal
Define line_total(quantity, unit_price, discount_pct=0.0) that returns quantity times unit_price times (1 minus discount_pct), rounded to 2 decimals. discount_pct is a fraction (0.15 means 15% off). Set result to the list [line_total(2, 49.99), line_total(3, 24.00, 0.15), line_total(1, 129.00, discount_pct=0.2)].
- Store a list of 3 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 Angela gets, and why
The lesson
Naming a piece of logic
A function is defined with def, a name, parameters in brackets, and a colon. The indented body
does the work, and return sends a value back to whoever called it:
def line_total(quantity, unit_price):
return quantity * unit_price
line_total(2, 49.99) # 99.98
Defining a function doesn’t run it. Python just remembers the recipe. It runs when you call it with brackets and actual values, called arguments. Inside the function, the parameters behave like ordinary variables that exist only for that call.
return versus print
print shows a value on screen; return hands it back so you can store it or use it in further
calculations:
total = line_total(2, 49.99) + 7.50 # works because line_total returns a number
A function without a return (or with a bare pass) returns None. That’s the most common
function bug for beginners: the function prints the right number, but every value built from it is
None, and the next line fails with TypeError: unsupported operand type(s) for +: 'NoneType' and 'float'.
return also ends the function immediately. Nothing after it in the body runs.
Default arguments
Most cart lines have no discount, so it would be tedious to pass 0 every time. Give the parameter
a default with = in the definition:
def line_total(quantity, unit_price, discount_pct=0.0):
return round(quantity * unit_price * (1 - discount_pct), 2)
line_total(2, 49.99) # 99.98 discount_pct is 0.0
line_total(3, 24.00, 0.15) # 61.2 15% off
Parameters with defaults must come after the ones without, so def f(a=1, b) is a syntax error.
Keyword arguments
You can pass any argument by name instead of position:
line_total(1, 129.00, discount_pct=0.2)
line_total(unit_price=129.00, quantity=1, discount_pct=0.2)
Named arguments make calls self-explanatory. Compare line_total(1, 129, 0.2) with the version
above: three months later, the second one still tells you what 0.2 means. pandas relies on this
heavily; calls like df.sort_values("unit_price", ascending=False) are everywhere.
Percentages: fraction or number?
Decide on one convention and say it in the function. Here discount_pct=0.15 means 15%. If
someone passes 15 by mistake, the “discounted” price becomes negative. Real datasets mix both
conventions, so always check a few values before using a discount column.
Docstrings
A short string right after the def line documents the function, and tools show it as help:
def line_total(quantity, unit_price, discount_pct=0.0):
"""Return the line total after a fractional discount, rounded to cents."""
return round(quantity * unit_price * (1 - discount_pct), 2)
Common mistakes
- Leaving
passin place or forgettingreturn, so every call givesNone. - Writing
discount_pctas a percentage (15) instead of a fraction (0.15). - Calling the function before defining it. Python reads top to bottom, so the
defmust run first.
Lantern lit!
Practised: defreturnparametersdefault argumentskeyword arguments
- Solved
- No hints
- First run
