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

Decimals & Widths

A placeholder can carry instructions as well as a value, after a colon — that second half has a name too, the format specification, though nobody says it out loud. There are a great many of them and you need two: .2f, which shows a number to two decimal places, and a width, which is what makes a column of output line up.

1.2f — for money, and for averages

Averages come out looking like this, and there is nothing wrong with them except that nobody wants to read one:

decimals.py
# rounding a number for display, without changing it

average = 74.66666666666667

print(average)
print(f'{average:.2f}')
print(f'{average:.1f}')
print(f'{average:.0f}')
print('and average is still', average)
Output
74.66666666666667
74.67
74.7
75
and average is still 74.66666666666667
{average:.2f}

Read it as three parts: the value, a colon, then the instruction. .2f means 'as a decimal number, with 2 digits after the point'. The f here stands for float and has nothing to do with the f that starts the string.

{average:.0f}

No digits after the point at all, so 74.666… shows as 75. It ROUNDS, it does not chop — which is the opposite of what int() would do.

print('and average is still', average)

The last line is the point of the whole section: nothing was changed. The formatting decided how the value was WRITTEN this once, and the variable still holds every digit it had.

Key Takeaway
Formatting is about display, not about the value. This is the difference between f'{x:.2f}' and round(x, 2): round() makes a new number that you might store and calculate with; an f-string just writes the one you have in a particular way. When the answer only needs to look tidy, format it — and keep the full value for the maths.

2A width — the thing that makes a table

Put a plain number after the colon and it is a minimum width: the value is padded with spaces until it fills that many characters. That is all it takes to line a table up:

widths.py
# lining a table up with a width

names = ['Asha', 'Ravindra', 'Meera']
marks = [72, 65, 88]

for i in range(len(names)):
    print(f'{names[i]:10} {marks[i]:5}')

print()

for i in range(len(names)):
    print(f'{names[i]:<10}|{marks[i]:>5}')
Output
Asha          72
Ravindra      65
Meera         88

Asha      |   72
Ravindra  |   65
Meera     |   88
Key Takeaway
Text and numbers pad in opposite directions by default. A string is pushed to the left of its width and a number to the right — which is exactly what you want, because names read from the left and digits line up on the right. The second loop writes it out anyway with < and >, so you can see the rule and override it.
{x:<10}
left

Pad on the right. The default for text.

{x:>10}
right

Pad on the left. The default for numbers.

{x:^10}
centre

Pad on both sides, as evenly as it can.

Watch Out
A width is a minimum, not a maximum. A name longer than ten characters is not cut short — it takes the room it needs and that row's column is pushed out of line. Choose the width from the longest value you expect, and know that an unexpected one will spoil the alignment rather than lose data.

3Both together: a bill

A width and a number of decimals go in the same instruction, width first: {total:8.2f} means “two decimal places, in a column eight characters wide”.

bill.py
# a bill, printed properly

item = 'Notebook'
price = 45.5
quantity = 3
total = price * quantity

print(f'{item:12} {quantity:3} x {price:7.2f} = {total:8.2f}')
print(f'Total payable: Rs {total:.2f}')
Output
Notebook       3 x   45.50 =   136.50
Total payable: Rs 136.50

45.5 printed as 45.50 — the second decimal place is there because money has two, not because the number does. That is a display decision, and it is exactly the kind of thing formatting is for.

bill.py

4How much of this to learn

Note
There is a lot more, and you do not need it. The instruction after the colon has its own small language — signs, commas for thousands, percentages, binary. For Class 11 the two on this page cover essentially every question: a number of decimal places for anything money-like or averaged, and a width for anything that has to line up. Meet the rest when a program actually needs it.
the whole of this page, on one card
Output
f'{x:.2f}'      74.67          two decimal places
f'{x:.0f}'      75             none — and it rounds
f'{name:10}'    'Asha      '   at least 10 wide, text goes left
f'{n:5}'        '   72'        at least 5 wide, numbers go right
f'{x:<10}'      left           force it left
f'{x:>10}'      right          force it right
f'{x:^10}'      centre         force it centre
f'{x:8.2f}'     '  136.50'     a width AND two decimals

5Recap

The instruction goes after a colon

{value:instruction}. The value is worked out first, exactly as before; the instruction only decides how it is written.

.2f rounds, and changes nothing

74.666… shows as 74.67 and the variable still holds every digit. round() makes a new number; formatting does not.

A plain number is a minimum width

Text pads to the left of it, numbers to the right — the defaults you want. < > ^ override them.

Two things to learn, not twenty

Decimal places and widths answer nearly every Class 11 question. The rest of the format language can wait.

Quick Check

average holds 74.66666666666667. After print(f'{average:.2f}'), what does average hold?

Quick Check

A name is 14 characters long and the format says {name:10}. What happens?

Quick Check

What does f'{45.5:7.2f}' produce?