F-Strings and String Formatting in Python
Master Python f-strings: embed variables, run expressions, format numbers and decimals, pad and align text, with clear line-by-line examples and a receipt project.
Key takeaways
- An f-string starts with f before the quote and puts variables inside {curly braces}
- You can run expressions inside the braces, like {price * 2}
- Format specifiers after a colon control decimals, padding and alignment, like {value:.2f}
- F-strings are clearer and faster than gluing strings together with +
The problem f-strings solve
Suppose you have a name and a score and want to print a friendly message. Beginners often write:
name = "Ada"
score = 95
print("Hello " + name + ", you scored " + str(score) + " points")
This works, but it is fiddly: you must add spaces by hand, glue pieces with +, and wrap the number in str() or Python complains. F-strings make the same line far cleaner.
This lesson assumes you know the basics of working with text and strings and Python input and output.
Your first f-string
name = "Ada"
score = 95
print(f"Hello {name}, you scored {score} points")
# Hello Ada, you scored 95 points
Two things make this an f-string:
- The letter
fimmediately before the opening quote. - The
{name}and{score}placeholders. Python replaces each one with the variable's value, converting numbers to text automatically. No+, nostr().
Expressions inside the braces
You are not limited to plain variable names. Any Python expression works inside the braces:
price = 8
print(f"Two cost {price * 2} pounds") # Two cost 16 pounds
word = "python"
print(f"Shout: {word.upper()}!") # Shout: PYTHON!
print(f"3 plus 4 is {3 + 4}") # 3 plus 4 is 7
Python evaluates whatever is between the braces, then drops the result into the string. This is why {price * 2} shows 16, not the literal text.
Formatting numbers
The most useful feature is the format specifier, written after a colon inside the braces. It controls how a value is displayed.
Decimal places
pi = 3.14159
print(f"Pi is about {pi:.2f}") # Pi is about 3.14
print(f"Pi is about {pi:.4f}") # Pi is about 3.1416
:.2f means "format as a float with 2 digits after the decimal point". Python rounds the displayed value for you. This is perfect for money and measurements.
Thousands separators
big = 1234567
print(f"Population: {big:,}") # Population: 1,234,567
The :, inserts commas to group thousands, making large numbers readable.
Percentages
ratio = 0.732
print(f"Score: {ratio:.0%}") # Score: 73%
:.0% multiplies by 100, adds a percent sign, and shows no decimals.
Padding and aligning text
Format specifiers can also set a width and alignment, which is ideal for tidy tables:
items = [("Apple", 3), ("Banana", 12), ("Cherry", 5)]
for name, qty in items:
print(f"{name:<8}{qty:>3}")
Output:
Apple 3
Banana 12
Cherry 5
{name:<8}left-aligns the name in a field 8 characters wide.{qty:>3}right-aligns the quantity in a field 3 characters wide, so the numbers line up neatly.
This loop uses tuple unpacking, which you can revisit in Python tuples and sets.
Worked example: a shop receipt
Let's combine these tools into a small program that prints a clean receipt.
cart = [
("Notebook", 2, 3.50),
("Pen", 5, 0.99),
("Eraser", 1, 1.20)
]
total = 0
print(f"{'Item':<10}{'Qty':>4}{'Price':>8}")
print("-" * 22)
for name, qty, price in cart:
line_cost = qty * price
total += line_cost
print(f"{name:<10}{qty:>4}{line_cost:>8.2f}")
print("-" * 22)
print(f"{'TOTAL':<10}{'':>4}{total:>8.2f}")
Output:
Item Qty Price
----------------------
Notebook 2 7.00
Pen 5 4.95
Eraser 1 1.20
----------------------
TOTAL 13.15
Step by step:
- The header uses left and right alignment so columns line up.
line_cost = qty * pricecalculates each row's cost;total += line_costadds it to the running total.{line_cost:>8.2f}combines width (8), alignment (right) and two decimal places — all in one specifier."-" * 22repeats a dash 22 times to draw a divider, a handy string trick.
Every column lines up because each value sits in a fixed-width field. Try doing that with + joins and you will appreciate f-strings instantly.
Common mistakes
- Forgetting the
f. Without it,"{name}"prints the literal braces instead of the value. - Putting the colon in the wrong place. Format instructions go after the value and a colon:
{value:.2f}, never{.2f:value}. - Confusing display with storage.
{pi:.2f}only changes howpilooks; the variable still holds the full number. - Quote clashes. Inside a double-quoted f-string, use single quotes for any inner strings.
Try it yourself
- Ask the user for a temperature in Celsius and print it converted to Fahrenheit with one decimal place using an f-string.
- Print a multiplication table for the number 7 where every product is right-aligned in a field 4 wide.
- Build a receipt for your own list of three items and show the total with a thousands separator and two decimals.
When you are comfortable, deepen your text skills with the Python string methods deep dive.
Quick quiz
Test yourself and earn XP
How do you start an f-string?
An f-string begins with f directly before the quote, like f"Hello".
What does f"{2 + 3}" produce?
Python evaluates the expression inside the braces, so it produces 5.
What does the specifier .2f do in f"{x:.2f}"?
.2f formats the value as a float with exactly two digits after the decimal point.
What separates a value from its format instructions inside the braces?
A colon separates the value from the format specifier, as in {value:.2f}.
Why are f-strings preferred over using + to join text and numbers?
F-strings read clearly and convert numbers to text automatically, avoiding str() calls and type errors.
FAQ
F-strings were added in Python 3.6, so any modern Python supports them. If you are on an older version you would use the older .format() method instead.
Yes, but use a different style than the outer quotes. If the f-string uses double quotes outside, use single quotes inside the braces, or the reverse, to avoid confusion.
Formatting with .2f only changes how the number is displayed as text; the underlying value is unchanged. round() actually changes the number you store.
Keep exploring
More in Coding