Formatting Output: .format, Alignment, Width and Precision
Why Exact Output Matters
Exam tasks often tell you exactly what the printed output should look like — a column of scores lined up, a price shown to two decimal places, a table with a header and a rule line underneath. The marks for these tasks depend on your program producing that exact layout, not just the right numbers in any order. A single missing space or the wrong number of decimal places can mean the output does not match what the mark scheme expects. This lesson covers the Programming Language Subset’s tools for controlling exactly how values appear on screen.
A PLS placeholder has the form {:<align><sign><width>.<precision><type>}. align is < (left), > (right) or ^ (centre). sign is + (show sign always), - (default, sign only on negatives) or a space (leading space on positives, minus on negatives). width is the total field width in characters. precision is the digits after the decimal point. type is d for whole numbers, f for fixed-point real numbers, or s for strings. Every part except the colon and braces is optional.
The .format Method and Placeholder Grammar
The PLS subprogram <string>.format (<values>) formats <values> and puts them into <string>. Each placeholder in the string is written between curly brackets, starting with a colon, and is replaced in order by the values passed to .format(). For example: "{:s}".format("Hi") produces Hi.
The align option controls where the value sits inside its field. "{:<10}|".format("Hi") gives Hi | (left-aligned, the default for strings). "{:>10}|".format("Hi") gives Hi| (right-aligned). "{:^10}|".format("Hi") gives Hi | (centred).
The sign option controls whether positive numbers show a +. "{:+d}".format(5) gives +5; "{:+d}".format(-5) still gives -5. Without a sign option, positive numbers show no sign at all — this is the default.
The width option sets the total field size. "{:5d}".format(7) gives 7 (four spaces then 7, since numbers are right-aligned by default). The precision option, written after a full stop, sets how many digits appear after the decimal point: "{:.2f}".format(3.14159) gives 3.14.
The type option tells Python what kind of value is being formatted. d means a whole number in base 10, f means fixed-point notation, and s means a string. If you leave out the type, Python assumes s for strings and d for whole numbers.
The PLS Worked Example, Character by Character
The PLS gives one canonical worked example combining all three options. Study the code and its output carefully, because this example from the PLS combines all three options — a string, an integer and a real number — in one format string.
layout = "{:>10} {:^5d} {:7.4f}"
print(layout.format('Fred', 358, 3.14159))Fred 358 3.1416
The first placeholder, {:>10}, right-aligns the string 'Fred' in a 10-character field. Fred is 4 characters, so 6 spaces are added before it.
The second placeholder, {:^5d}, centres the integer 358 in a 5-character field. 358 is 3 characters, so one space is added on each side, giving " 358 ".
The third placeholder, {:7.4f}, formats 3.14159 as fixed-point with 4 digits after the decimal point, rounding it to 3.1416, then right-aligns that 6-character result in a 7-character field — adding one leading space. The single spaces between the three placeholders in the string layout are literal characters typed between the braces, not part of any field.
Printing a Table of Records
Combining fixed widths across a header row and every data row is how you print a neatly aligned table of records — a list of lists. Use the same width for a column in the header and in every row so the columns line up, and use the * operator to draw a rule line under the header: "=" * 10 generates ==========.
records = [["Amir", 82], ["Priya", 95], ["Jack", 47]]
header = "{:<10}{:>6}".format("Name", "Score")
rule = "-" * 16
print(header)
print(rule)
for row in records:
print("{:<10}{:>6}".format(row[0], row[1]))Name Score ---------------- Amir 82 Priya 95 Jack 47
Notice that the numbers all end at the same column, even though the header word Score is longer than the data values. Right-aligning a fixed-width numeric column is what keeps the digits lined up underneath each other, whatever the number of digits each value has.
Money, Averages and Rounding
The built-in subprogram round (<x>, <n>) rounds <x> to <n> digits after the decimal, using the 0.5 rule, and returns a real number. This is different from formatting a value for display, which only changes how a value looks on screen without changing the value stored in the variable.
total = 20.0
print(round(total, 2))
print("{:.2f}".format(total))20.0 20.00
Both lines round to two decimal places, but only the second guarantees two digits are shown. round() does not force a trailing zero to appear, so a rounded price of exactly 20 prints as 20.0. A format placeholder with .2f always shows exactly two digits, which is why it is the safer choice for displaying money.
round (<x>, <n>) returns a new rounded number, so if you store that result, later maths uses the rounded figure. A format placeholder such as {:.2f} only changes how a value is displayed when printed — the original variable is unchanged. Use round() when the rounded value itself matters; use a format placeholder when you only need a tidy display.
Joining Values and Breaking Long Lines
Strings can be joined with the + operator, called concatenation. Numbers cannot be concatenated directly to a string — they must be converted with str() first.
name = "Amir" score = 82 message = name + " scored " + str(score) + " points" print(message)
Amir scored 82 points
A line built from many concatenated parts, or a long .format() call, can scroll off the screen. The PLS supports line continuation using a backslash character at the end of a line, or by simply breaking the line inside round () or square [] brackets, which Python allows without any extra symbol.
print("{:<10}{:>6}".format( "Name", "Score"))Four mistakes come up again and again with formatted output:
- Giving
.format()fewer values than there are placeholders raises an error (an IndexError); note that surplus values are simply ignored, so a mismatch will not always be reported. - Forgetting the colon after the opening brace, so Python cannot tell where the field name ends and the format options begin.
- Using type
don a real number instead off, which causes an error becausedexpects a whole number. - Expecting quotation marks to appear in printed output —
print("Fred")displaysFred, never"Fred".