LambdaLabTM
Computer Science · Class 11 · More about print()
print()Programs⏱️ 13 min read

Programs with f-strings

Three programs you have already written in an earlier chapter, printed the way somebody would actually want to read them. Nothing about the working changes — the arithmetic is the same, the loops are the same. Only the last few lines are different, and they are the ones the reader sees.

1Program 1 — a shop bill with GST

📋 The problem

Ask for an item, its price and how many, then print a bill with the amount, 18% GST and the total payable — all lined up, all to two decimal places.

Input
what we ask the user for
  • the item name
  • the price, as a float
  • the quantity, as an int
Process
what we work out
  • total = price * quantity
  • 18% of the total
  • the two added together
Output
what we show
  • six lines, with the figures in a column
bill.py
# a shop bill, from the user

item = input('Item name: ')
price = float(input('Price per unit: '))
quantity = int(input('How many? '))

total = price * quantity
gst = total * 18 / 100
payable = total + gst

print()
print(f'Item     : {item}')
print(f'Rate     : {price:10.2f}')
print(f'Quantity : {quantity:10}')
print(f'Amount   : {total:10.2f}')
print(f'GST @18% : {gst:10.2f}')
print(f'Payable  : {payable:10.2f}')
Output
Item name: Notebook
Price per unit: 45.5
How many? 3

Item     : Notebook
Rate     :      45.50
Quantity :          3
Amount   :     136.50
GST @18% :      24.57
Payable  :     161.07
print(f'Rate : {price:10.2f}')

The labels are padded by hand with spaces so they are all the same length; the figures are padded by the width 10 so they end in the same column. Both halves matter — a column is only a column when both sides line up.

{quantity:10}

A width but no decimals, because a quantity is a whole number. It still lands in the same column, because numbers pad to the right.

gst = total * 18 / 100

Worked out in full and stored in full — 24.57 on screen is 24.57 exactly here, but on other numbers the stored value would carry more digits. The formatting is display only; the arithmetic never sees it.

Key Takeaway
Two decimal places is a rule about money, not about Python. 45.5 is a perfectly good number and Rs 45.5 is not a perfectly good price. .2f is how you say “this is money” in output — and it is the reason every bill program in the projects chapter uses it.
bill.py

2Program 2 — a mark sheet with a heading row

📋 The problem

Print a table of names and marks out of 150, with a percentage column and a heading row that lines up with the data underneath it.

marksheet.py
# a mark sheet, out of 150, lined up

names = ['Asha', 'Ravindra', 'Meera', 'Karan']
marks = [128, 96, 141, 74]
out_of = 150

print(f'{"Name":12}{"Marks":>7}{"Percent":>10}')

for i in range(len(names)):
    percent = marks[i] / out_of * 100
    print(f'{names[i]:12}{marks[i]:7}{percent:10.1f}')

total = 0

for m in marks:
    total = total + m

print()
print(f'Class average : {total / len(marks):.2f} out of {out_of}')
print(f'Class percent : {total / len(marks) / out_of * 100:.1f}%')
Output
Name          Marks   Percent
Asha            128      85.3
Ravindra         96      64.0
Meera           141      94.0
Karan            74      49.3

Class average : 109.75 out of 150
Class percent : 73.2%
Key Takeaway
The heading row uses the same widths as the data row. That is the whole trick of a table: 12, 7 and 10 appear twice, once in the heading and once in the loop. Change one and you have to change the other — which is why the two lines are worth writing one under the other, where the numbers can be compared at a glance.

The headings are right-aligned with > because they sit over numbers, and numbers pad right. The name heading is not, because it sits over text. A heading should be aligned the way its column is, or the table looks broken even though every row is correct.

Watch Out
The percentage is worked out in the loop, not stored. percent is made fresh on every round from marks[i], so nothing has to be kept in step. Storing a second parallel list of percentages would be one more thing that can drift out of line with the marks.

3Program 3 — the multiplication table, lined up

📋 The problem

Print a multiplication table where the numbers line up in columns however many digits they have.

table_lined.py
# the multiplication table, lined up

num = int(input('Which table? '))

for i in range(1, 11):
    print(f'{num:3} x {i:2} = {num * i:4}')
Output
Which table? 7
  7 x  1 =    7
  7 x  2 =   14
  7 x  3 =   21
  7 x  4 =   28
  7 x  5 =   35
  7 x  6 =   42
  7 x  7 =   49
  7 x  8 =   56
  7 x  9 =   63
  7 x 10 =   70

Look at the 10 in the second column and the two-digit answers in the third. Without the widths, the x and the = would shuffle left and right from row to row — the same table, and much harder to read. Widths of 3, 2 and 4 were chosen from the longest value each column can hold: a table up to 10 needs two characters for the counter and four for a product like 1000.

table_lined.py

4Where this leaves the whole chapter

sep — what goes between the values

Dates, paths, comma lists. One print(), several values, a punctuation mark in the gaps.

end — what goes after them

Anything that has to stay on one line: tables, dots, patterns. Something afterwards supplies the newline.

f-strings — what the sentence looks like

A value inside a sentence, with no str() and no joining. And after a colon, how that value should be written.

Note
You will still see the older ways, and they are not wrong. Plenty of textbooks and papers join with + and str(), or use commas and accept the spaces. Every program in the chapters after this one does, because they were written to work without this chapter. Read all three comfortably; write whichever the question asks for, and the f-string when it is your own program.
✍️ Now write these yourself
  1. 1

    Print a receipt for three items, each with a name, a quantity and a price, all in columns.

    Hint · Three parallel lists and one loop, with the same widths in the heading row and the data row.

  2. 2

    Print the temperature in Celsius and Fahrenheit to one decimal place, for 0 to 100 in steps of 10.

    Hint · f = c * 9 / 5 + 32, and {c:6.1f} for both columns.

  3. 3

    Print a list of items and their prices with the total at the bottom, right-aligned in one column.

    Hint · One width for the whole column, used on every line including the total.

  4. 4

    Show the square and cube of 1 to 10 in three lined-up columns.

    Hint · Widths chosen from the biggest value: 1000 needs four characters.

  5. 5

    Print the time as 09:45:00 from three separate numbers.

    Hint · This is the one sep could not do. {h:02} pads with zeros instead of spaces — try it and see.

Quick Check

Why do the heading row and the data row use the same widths?

Quick Check

In the bill program, gst holds a long decimal but prints as 24.57. What is stored?

Quick Check

Why is the Marks heading written as {'Marks':>7} rather than {'Marks':7}?