Skip to main content
Learning Center
Python Programming

Module 1: Values, Variables, and Expressions

Formatted Output and Untidy Text

Format specifications that make numbers readable, the string methods that make published text comparable, and why cleaning is a separate step from displaying.

Lesson 6 of 46 in the recommended order · About 25 min (estimate)

On this page

Outcome

By the end of this lesson you can render numbers and text into output a person can scan quickly, and you can clean inconsistent published text so that two records describing the same thing actually compare as the same thing.

Why it matters

Real published data is untidy in boring, consistent ways: trailing spaces, mixed capitalisation, a code written three different ways by three different offices. None of that is a bug in the publisher's system; it is what happens when many people type into many forms over many years.

Two things follow. First, output has to be formatted deliberately or a reviewer cannot scan it. Second, cleaning is a separate step from displaying, and confusing the two is how a display tweak silently changes the data you are storing.

Concept

Inside an f-string, everything after a colon is a format specification, and it affects only the rendering.

  • {value:,} inserts thousands separators.
  • {value:.2f} renders a number with exactly two decimal places.
  • {value:>12} right-aligns in a field twelve characters wide; < left-aligns, ^ centres.
  • Combining them works: {value:>12,.2f}.

Text has methods, which are functions you call on the value itself with a dot. The ones you need constantly:

  • .strip() removes whitespace from both ends, and only the ends.
  • .upper(), .lower(), and .title() change case. .title() capitalises the first letter of each word.
  • .replace(old, new) substitutes every occurrence.
  • .startswith(prefix) and .endswith(suffix) answer a yes/no question and return a bool.

Every one of these returns a new string. None of them modifies the value in place, because text in Python cannot be modified in place at all. title.strip() on its own line accomplishes nothing; you have to bind the result to a name.

One environment note: local Python has input() for reading a typed answer. The in-page runner has no keyboard channel into the interpreter, so exercises here use values already in the code. Nothing you learn is lost; input() is a one-line change when you move a program to your own machine.

Read the code

raw_agency = "  Dept of Transportation  "
raw_status = "ACTIVE"
amount = 4820.5

agency = raw_agency.strip()
status = raw_status.title()

print(f"{'Agency':<10}{agency}")
print(f"{'Status':<10}{status}")
print(f"{'Amount':<10}{amount:>12,.2f}")

The first three names hold the record exactly as published, untidy parts included. The next two produce cleaned copies under different names, which leaves the originals available if you ever need to prove what was published.

The three print lines separate layout from data. {'Agency':<10} left-aligns a literal label in a ten-character column, so the three values line up underneath each other. {amount:>12,.2f} right-aligns the number in a twelve-character column with separators and two decimals, which is how columns of money are read.

Predict the output

Predict the three printed lines, paying attention to where the spaces fall.

Check your prediction
Agency    Dept of Transportation
Status    Active
Amount        4,820.50

Each label occupies ten characters, so the second column starts at the same place on all three lines. The amount is pushed to the right-hand edge of its twelve-character field, which is why it does not begin where the two text values do. "ACTIVE".title() produces "Active", not "ACTIVE".

Modify the code

Change {amount:>12,.2f} to {amount:<12,.2f} and predict what happens to the third line.

What changes, and why

The amount moves left, starting in the same column as the two text values: Amount 4,820.50. It reads more consistently with the lines above and worse as a number, which is the actual trade-off. Numbers are compared digit by digit from the right, so right-aligning them lets a reader spot an order-of-magnitude difference instantly. Aligning text left and numbers right is a convention with a reason behind it.

Debug the bug

An assistant was asked to trim the whitespace from a published agency name before printing it. It produced this and said the output would have no leading spaces.

raw_agency = "  Dept of Transportation  "

raw_agency.strip()

print(f"[{raw_agency}]")
What's actually wrong

It prints [ Dept of Transportation ], spaces intact. The program runs cleanly and does the wrong thing, which is the hardest of Module 0's three failure kinds to notice.

.strip() returns a new cleaned string; it cannot change raw_agency, because strings are immutable. Line 3 computes the cleaned value and immediately discards it, exactly like the total + 0 line in the previous lesson.

Both fixes are one line. raw_agency = raw_agency.strip() rebinds the same name to the cleaned value. agency = raw_agency.strip() keeps both, which is usually better when the original is data someone published and you may need to cite.

The square brackets in the print are worth stealing as a habit: wrapping a value in visible delimiters is the fastest way to see whitespace you would otherwise miss.

Try it yourself

Two fields from a listing, carrying the untidiness real listings carry. Print one display line that shows the agency code with no surrounding spaces and in capitals, and the description in title case.

Loading this exercise…

Practical challenge (optional)

Optional: write down the cleaning rules you just applied as a short list in plain English, one line each, in the order they must run. Then add a rule for a case you have not handled: an agency code published as GSA R7 with a space instead of a hyphen. Which method fixes it, and does it have to run before or after .upper()? Writing rules down before coding them is the same habit that produces a usable data dictionary in Module 6.

Sign in to track your progress on this exercise.

AI collaboration

Checkpoint

For each line, say what it prints, or say that it produces no visible effect:

  1. print(f"{7:>5}")
  2. print(f"{0.5:.1%}")
  3. " code ".strip()
  4. print("GSA-R7".lower().startswith("gsa"))
  5. print(f"{'total':^9}|")
Answers
  1. Four spaces then 7, right-aligned in a five-character field.
  2. 50.0%. The % format spec multiplies by a hundred and appends the sign, which is why a rate is stored as 0.5 rather than 50.
  3. Nothing visible. It computes a cleaned string and discards it, the bug from Debug the Bug.
  4. True. The lowercase copy starts with gsa, and the comparison produces a boolean.
  5. total |. The word is centred in a nine-character field, so two spaces fall on each side.

Sign in to track your progress on this exercise.

Summary and next step

You can now align and round output deliberately, clean published text with methods that return new values rather than modifying old ones, and keep the cleaned copy separate from what was published. Module 2 turns those cleaned values into decisions: comparisons, boolean logic, and the first explainable matching rule for the review assistant.

learning.goultergroup.com

The interactive parts of this page have not loaded. Reading and links still work; reload the page to try again.