Warm-up · Activity 1 of 7
// B5.2 · ~25 min · Beginner
Formatted output with f-strings
After this lesson you can print values in tidy columns with f-strings, round them to fixed decimals with thousands separators, and show exactly what a variable holds while debugging.
Predict · Activity 2 of 7
Predict before you read on: what does this print?
price = 3.14159 print(f"Total: {price:.2f} EUR")Practice · Activity 3 of 7
Fill in the format spec so that the number prints as 84,607,016.
population = 84607016 print(f"{population:____}"){population:}Practice · Activity 4 of 7
The | characters show where each field ends. What does this print?
print(f"{'Tea':<6}|{2.5:>6.2f}|")Practice · Activity 5 of 7
x = 1234.567. Match each f-string to the text it produces.
Brain teaser · Activity 6 of 7
Brain teaser. Both fields have the same width and no alignment. What does this print?
print(f"[{'ab':5}][{42:5}]")Apply · Activity 7 of 7
Mini-task. Print a receipt for items = [("Coffee", 3.2), ("Bagel", 2.75), ("Juice", 4.5)]: each name left-aligned in 10 characters, each price right-aligned in 8 characters with two decimal places, and a last line Total with the sum in the same columns.
Check your work against this list
Build it yourself
Read the worked example, then write the exercises. Your code runs in your browser or on your computer and is never uploaded.
Worked example
A monthly budget table
Three expenses are printed as a table: names left-aligned, amounts right-aligned with two decimal places, and a total with a thousands separator. Two debugging lines follow: the = specifier with a percentage format, and str.format with !r, which shows the quotes around a string.
main.py
items = [("Rent", 950.0), ("Groceries", 312.456), ("Internet", 39.9)]
total = sum(price for _, price in items)
print(f"{'Item':<12}{'EUR':>10}")
for name, price in items:
print(f"{name:<12}{price:>10.2f}")
print("-" * 22)
print(f"{'Total':<12}{total:>10,.2f}")
rent_share = items[0][1] / total
print(f"{rent_share = :.1%}")
print("{} items, the first is {!r}".format(len(items), items[0][0]))
Run it with
python main.pyOutput
Item EUR
Rent 950.00
Groceries 312.46
Internet 39.90
----------------------
Total 1,302.36
rent_share = 72.9%
3 items, the first is 'Rent'- 312.456 prints as 312.46 and 39.9 as 39.90: .2f always shows exactly two decimals.
- The headers are strings, so they need < and > to match the columns below them.
- rent_share = keeps the spaces around =, and :.1% multiplies by 100 and adds a percent sign.
- {!r} in str.format works like !r in an f-string: the string is shown with its quotes.
Change it and run it
Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.
The first run downloads Python for your browser (up to 6.5 MB) and keeps it cached. Your code stays on your device.
Exercises
Exercise 1 of 2
A receipt line
Write format_line(name, qty, price) that returns one receipt line: the name left-aligned in 10 characters, the quantity right-aligned in 3, then " x ", then the price right-aligned in 7 characters with two decimal places. format_line("Tea", 2, 3.5) returns "Tea 2 x 3.50", 23 characters in all.
Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.
The first run downloads Python for your browser (up to 6.5 MB) and keeps it cached. Your code stays on your device.
Hints
Hint 1
Each value gets its own format spec after a colon: {name:<10}, {qty:>3} and {price:>7.2f}.
Hint 2
Everything outside the braces is copied as it is, so " x " goes straight into the f-string between qty and price.
Hint 3
return f"{name:<10}{qty:>3} x {price:>7.2f}"
Show a solution
One way to solve it. Yours can look different and still pass the checks.
def format_line(name: str, qty: int, price: float) -> str:
return f"{name:<10}{qty:>3} x {price:>7.2f}"
if __name__ == "__main__":
print(format_line("Tea", 2, 3.5))
print(format_line("Croissant", 12, 1.25))
Run it on your computer
Install Python 3.14 or newer. Save these files in one folder, open a terminal in that folder, and run the commands below.
main.py
def format_line(name: str, qty: int, price: float) -> str:
return f"{name} {qty} x {price}"
if __name__ == "__main__":
print(format_line("Tea", 2, 3.5))
print(format_line("Croissant", 12, 1.25))
test_main.py
from main import format_line
def test_tea():
"""Tea, 2, 3.5 gives the example line"""
got = format_line("Tea", 2, 3.5)
assert got == "Tea 2 x 3.50", f"format_line(\"Tea\", 2, 3.5) returned {got!r}"
def test_width():
"""Every line is 23 characters long"""
got = format_line("Croissant", 12, 1.25)
assert len(got) == 23, f"the line {got!r} has {len(got)} characters, expected 23"
def test_two_decimals():
"""Prices always show two decimal places, rounded"""
got = format_line("Cake", 1, 12.349)
assert got.endswith(" 12.35"), f"for 12.349 the line ends with {got[-7:]!r}, expected ' 12.35'"
def test_columns():
"""Name, quantity and price sit in their columns"""
got = format_line("Jam", 10, 150.0)
assert got == "Jam 10 x 150.00", f"format_line(\"Jam\", 10, 150.0) returned {got!r}"
On macOS and Linux, type python3 wherever these commands say python, as in the first lesson.
Run the program:
python main.pyRun the checks (needs learnrun.py in the same folder):
python learnrun.py testDownload learnrun.pyExercise 2 of 2
Money and percentages
Write two functions. money(amount) returns the amount with a thousands separator and two decimals, followed by " EUR": money(1234.5) is "1,234.50 EUR". percent(part, whole) returns part / whole as a percentage with one decimal place: percent(1, 8) is "12.5%". Use the format specs , .2f and .1% rather than rounding by hand.
Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.
The first run downloads Python for your browser (up to 6.5 MB) and keeps it cached. Your code stays on your device.
Hints
Hint 1
In a format spec the comma comes before the precision: {amount:,.2f}.
Hint 2
The % type multiplies by 100 and adds the percent sign itself, so pass the fraction part / whole, not part / whole * 100.
Hint 3
return f"{part / whole:.1%}"
Show a solution
One way to solve it. Yours can look different and still pass the checks.
def money(amount: float) -> str:
return f"{amount:,.2f} EUR"
def percent(part: float, whole: float) -> str:
return f"{part / whole:.1%}"
if __name__ == "__main__":
print(money(1234.5), percent(1, 8))
Run it on your computer
Install Python 3.14 or newer. Save these files in one folder, open a terminal in that folder, and run the commands below.
main.py
def money(amount: float) -> str:
return str(amount) + " EUR"
def percent(part: float, whole: float) -> str:
return str(part / whole * 100) + "%"
if __name__ == "__main__":
print(money(1234.5), percent(1, 8))
test_main.py
from main import money, percent
def test_money_separator():
"""1234.5 becomes 1,234.50 EUR"""
got = money(1234.5)
assert got == "1,234.50 EUR", f"money(1234.5) returned {got!r}"
def test_money_small_and_large():
"""0.5 and 2500000 get two decimals and separators"""
got = money(0.5), money(2500000)
assert got == ("0.50 EUR", "2,500,000.00 EUR"), f"money(0.5) and money(2500000) returned {got!r}"
def test_percent():
"""1 of 8 is 12.5%, and 2 of 3 is 66.7%"""
got = percent(1, 8), percent(2, 3)
assert got == ("12.5%", "66.7%"), f"percent(1, 8) and percent(2, 3) returned {got!r}"
On macOS and Linux, type python3 wherever these commands say python, as in the first lesson.
Run the program:
python main.pyRun the checks (needs learnrun.py in the same folder):
python learnrun.py testDownload learnrun.pyCommon mistakes
Formatting a string as a number
value = "3.5" # what input() gives you: a string
print(f"{value:.1f}")
What Python prints
ValueError: Unknown format code 'f' for object of type 'str'Why, and the fix
The f type only works on numbers, and input() always returns a string. Convert first: value = float(input()). Then f"{value:.1f}" works.
Too few arguments for str.format
print("{} scored {}".format("Ada"))
What Python prints
IndexError: Replacement index 1 out of range for positional args tupleWhy, and the fix
Each empty {} takes the next argument, and the second one, index 1, has none. Pass one argument per placeholder, or use an f-string, where the values sit inside the braces and cannot go missing: f"{name} scored {score}".
Using d for a float
total = 2.5 * 4
print(f"{total:,d}")
What Python prints
ValueError: Unknown format code 'd' for object of type 'float'Why, and the fix
d is for integers, and 2.5 * 4 is the float 10.0. Use .0f to show a float without decimals, f"{total:,.0f}", or convert it with int(total) if it must be a whole number.
Python in the browser: Pyodide 314.0.7, MPL-2.0. Licence and source
Exit ticket
5 questions, no hints. Score 80% or more to complete the lesson.
Finish every activity above to unlock the exit ticket.