Skip to content

Exercise 10 of 10 · A complete program

The Cafe Ticket

What you will make

A printed cafe receipt with the shop name at the top, three item rows in straight columns, a subtotal, a service charge the program works out itself, a total, and a thank-you line at the bottom.

The one new idea: Assembling a complete program from parts you already know

Nothing in this program is new, and that is the point. Real software is almost never one clever idea; it is a handful of ordinary ones stacked in the order the work happens. Once you can look at a finished program and name the parts, you can read other people's code and keep building your own.

Go straight to the code ↓

Nothing new, all at once

Every exercise so far handed you one new idea and somewhere small to try it. This one hands you no new idea at all. Every line in the editor is something you have already met.

That is what a finished program is. Not one clever trick, but a handful of ordinary ones arranged in the order the work actually happens. Here is this receipt, named piece by piece:

  • print puts each line on the screen. That was the very first thing you wrote.
  • Variables hold the parts that change: name, qty, price.
  • Arithmetic turns them into amounts: qty * price for one row, subtotal // 10 for a tenth of the bill.
  • An if decides whether the service charge applies to this order at all.
  • An f-string with widths — {name:<12}, {cost:>6} — is what makes the columns land in a straight line instead of wandering.
  • A list and a for loop print the small notes at the bottom without a separate print for each one.
  • A running total collects the order as it goes, exactly as it collected the week of rainfall.

Seven ideas, none of them new here, all of them in one receipt.

The running total, one more time

subtotal = 0 sits above the items, and then subtotal = subtotal + cost appears once per item. It is the same line you wrote for the rainfall, doing the same job on different values: work out the right-hand side first, using whatever subtotal holds now, then store the answer back under the same name. The rainfall chart had a loop repeat that line for it; here the three items sit one under the other, so it is repeated by hand. The pattern does not mind either way.

It sits behind every bill, every score and every count you will write. A total is not typed. It is collected.

A worked example

A market stall rather than a cafe, so the receipt in the editor stays yours to finish:

Python
total = 0

name = "Apples"
qty = 4
price = 12
cost = qty * price
total = total + cost
print(f"{name:<8}{cost:>5}")

name = "Bread"
qty = 1
price = 30
cost = qty * price
total = total + cost
print(f"{name:<8}{cost:>5}")

print("-------------")
print(f"TOTAL{total:>8}")
Output
Apples     48
Bread      30
-------------
TOTAL      78

Two blocks of the same six lines with different values in them, and a total nobody typed in. Change the 4 to a 5 and both the apples row and the total move with it, because both are worked out rather than written down.

Your turn

Press Run before changing anything. Most of the receipt is already correct: the header, the first two item rows, the service charge, the notes at the bottom.

Two lines are marked, and both of them already run. They are wrong, not missing.

  1. The cake's row still prints its four values with commas, so the numbers land nowhere near the columns above them. Rewrite it as an f-string matching the two rows above it. The widths you need are on those rows.
  2. total is set to 0, so the bottom of the receipt disagrees with the rest of it. Work the total out from the two values the program already has: the amount for the items, and the service charge.

Then change something: the cake to two slices, the chai to another price. Run it again. The row, the subtotal, the service charge and the total should all move together. That is the difference between a receipt that is worked out and one that is typed.

If something goes wrong

The likeliest slip is the total, and it announces itself: the TOTAL line shows 0, or a number that does not match the two above it. Check that both names on the right of the = are spelled as they are spelled further up, and that the line still sits below the service charge — Python works down the page, so a value has to exist before it can be added to anything.

If the cake row prints {name:<12} at you word for word, the f in front of the quote is missing. If it prints but sits out of line, count the widths against the two rows above rather than guessing; one number different is all it takes.

Nothing here can break. Change the order, run it again, and read your own receipt.

Write your code

Runs in your browser. Press Run (or Ctrl/Cmd+Enter) and the output is checked for you.

Ctrl/Cmd+Enter to run

Press Esc then Tab to move keyboard focus out of the code editor.

Ready
Output will appear here after you run your code.

The runtime is starting in the background. You can type now — it will be ready before you are.

The answer appears here once you have run your code at least once.

Things that often go wrong here

Typing the final total in by hand
The number is right this minute and wrong the moment anything changes. Order two slices of cake instead of one and the rows and the subtotal update themselves, while a typed total sits underneath contradicting them. A total is worked out from the values above it, never copied off the screen.
Leaving the f off the front of the quote
Without the f the curly braces are ordinary characters, so the cake row prints them back at you word for word instead of the values. No error appears, because a piece of text with braces in it is a perfectly legal thing to want.
Giving the cake row different widths from the rows above it
The rows line up only because every one of them gives the name twelve characters, the quantity three, the price five and the amount six. Change one of those numbers on one row and that row alone drifts out of column while the others stay put.
Writing total = cost + service
cost holds the amount for the last item only, because each block overwrites it with its own figure, so the receipt totals 69 instead of 154. The variable that has been collecting the whole order is subtotal.

Longer explanation: read the full lesson. Want a blank editor instead? Open the Python playground.