Python String Formatting and F-Strings
String Formatting and F-Strings
Programs constantly combine text with values: "Your order total is ₹1,250.00", "Welcome back, Asha!", "Upload 87% complete". String formatting is the process of inserting values into text and controlling how they appear — the number of decimal places, alignment, thousands separators, and more.
Python offers two main tools for this:
- F-strings (formatted string literals) — introduced in Python 3.6 and now the recommended approach
- The
format()method — the older approach, still widely seen in existing code
Before Python 3.6, developers mainly used format() or string concatenation with +, which is more verbose, harder to read, and requires manual conversion with str().
What Are F-Strings?
An f-string lets you embed values and expressions directly inside a string. To create one, put the letter f (or F) before the opening quote.
Example: A Basic F-String
message = f"Welcome to Python programming"
print(message)
Expected output:
Welcome to Python programming
This f-string contains no placeholders, so it behaves like a normal string. The power of f-strings comes from placeholders.
Using Placeholders
Values are inserted into an f-string with curly braces {}. Each pair of braces is a placeholder, and it can contain:
- Variables
- Calculations and other expressions
- Function and method calls
- Formatting modifiers
Example: Inserting a Variable
score = 88
result = f"Your final score is {score}"
print(result)
Expected output:
Your final score is 88
Python evaluates score, converts its value to text automatically, and inserts it where the placeholder is. No str() conversion is needed.
Comparison With Concatenation
name = "Asha"
age = 25
# Concatenation: requires str() and careful spacing
print("Name: " + name + ", Age: " + str(age))
# F-string: clear and concise
print(f"Name: {name}, Age: {age}")
Expected output:
Name: Asha, Age: 25
Name: Asha, Age: 25
Formatting Values With Modifiers
A format specifier (also called a modifier) controls how a value is displayed. It is written after a colon inside the placeholder:
f"{value:specifier}"
Example: Limiting Decimal Places
average = 7.45678
output = f"Average rating: {average:.2f}"
print(output)
Expected output:
Average rating: 7.46
.2f means "format as a fixed-point number with 2 decimal places". The value is rounded for display only — the variable average is unchanged.
Example: Formatting a Literal Value Directly
output = f"Success rate: {92.347:.1f}%"
print(output)
Expected output:
Success rate: 92.3%
The % after the closing brace is ordinary text.
Performing Operations Inside F-Strings
Any valid Python expression can be placed inside the braces.
Example: Arithmetic
total = f"Total cost: {15 * 120} rupees"
print(total)
Expected output:
Total cost: 1800 rupees
Example: Calculation Using Variables
price = 500
discount = 0.10
final_price = f"Payable amount: {price - (price * discount)}"
print(final_price)
Expected output:
Payable amount: 450.0
The result is a float (450.0) because price * discount produces a float. Adding a modifier, such as {price - (price * discount):.2f}, would display 450.00.
Tip: For complex calculations, compute the value in a separate variable first and then insert it. This keeps f-strings short and readable.
Conditional Logic Inside F-Strings
A conditional expression (value_if_true if condition else value_if_false) can choose what to display.
marks = 72
status = f"Result: {'Pass' if marks >= 40 else 'Fail'}"
print(status)
Expected output:
Result: Pass
Notice that the f-string uses double quotes, while the strings inside the placeholder use single quotes. In Python versions before 3.12, reusing the same quote type inside a placeholder causes a syntax error, so alternating quote types is the safest habit.
Calling Functions Inside F-Strings
Both built-in and user-defined functions — and methods — can be called inside placeholders.
Example: Calling a String Method
city = "chennai"
text = f"I live in {city.title()}"
print(text)
Expected output:
I live in Chennai
title() is a string method that capitalizes the first letter of each word.
Example: Calling a User-Defined Function
def km_to_miles(km):
return km * 0.621371
distance = f"Distance: {km_to_miles(10):.2f} miles"
print(distance)
Expected output:
Distance: 6.21 miles
The function is called first, and its result (6.21371) is then formatted to two decimal places.
Advanced Formatting Options
Thousands Separator
population = 14500000
info = f"Population: {population:,}"
print(info)
Expected output:
Population: 14,500,000
The comma specifier inserts a comma every three digits. An underscore works the same way: {population:_} produces 14_500_000.
Percentage Format
progress = 0.875
status = f"Completed: {progress:.0%}"
print(status)
Expected output:
Completed: 88%
The % specifier multiplies the value by 100 and adds a percent sign. .0% shows no decimal places, so 87.5% is rounded to 88%. With .1%, the result would be 87.5%.
Alignment and Width
A number before the type sets the minimum width, and <, >, or ^ sets the alignment.
print(f"[{'Hi':<6}]")
print(f"[{'Hi':>6}]")
print(f"[{'Hi':^6}]")
Expected output:
[Hi ]
[ Hi]
[ Hi ]
The square brackets show the edges of each 6-character field.
Practical Example: A Formatted Table
items = [("Notebook", 3, 45.0), ("Pen", 10, 12.5), ("Bag", 1, 899.0)]
print(f"{'Item':<10}{'Qty':>5}{'Price':>10}")
for name, qty, price in items:
print(f"{name:<10}{qty:>5}{price:>10.2f}")
Expected output:
Item Qty Price
Notebook 3 45.00
Pen 10 12.50
Bag 1 899.00
Each column has a fixed width, so the values line up neatly regardless of their length.
Number Bases and Signs
print(f"{5:+}")
print(f"{10:b}")
print(f"{255:x}")
print(f"{255:X}")
print(f"{8:o}")
print(f"{12345.678:e}")
Expected output:
+5
1010
ff
FF
10
1.234568e+04
Debugging With =
Since Python 3.8, adding = after an expression prints both the expression and its value — handy for debugging:
x = 5
print(f"{x=}")
print(f"{x * 2=}")
Expected output:
x=5
x * 2=10
Displaying Literal Braces
To show a literal { or } in an f-string, double it:
print(f"{{value}} is replaced by {42}")
Expected output:
{value} is replaced by 42
Common Format Specifiers
| Specifier | Description | Example | Result |
|---|---|---|---|
< | Left-align within the width | f"{'Hi':<6}" | 'Hi ' |
> | Right-align within the width | f"{'Hi':>6}" | ' Hi' |
^ | Center within the width | f"{'Hi':^6}" | ' Hi ' |
+ | Always show the sign | f"{5:+}" | +5 |
, | Comma thousands separator | f"{1000000:,}" | 1,000,000 |
_ | Underscore thousands separator | f"{1000000:_}" | 1_000_000 |
b | Binary | f"{10:b}" | 1010 |
d | Decimal integer | f"{42:d}" | 42 |
f | Fixed-point number | f"{3.14159:.2f}" | 3.14 |
e | Scientific notation | f"{12345.678:e}" | 1.234568e+04 |
o | Octal | f"{8:o}" | 10 |
x / X | Hexadecimal (lower/upper case) | f"{255:x}" | ff |
% | Percentage | f"{0.875:.1%}" | 87.5% |
String Formatting With format()
Before f-strings, the format() method was the standard way to format strings. It is still supported and useful when a template string is defined separately from the values — for example, a message template loaded from a configuration file. However, f-strings are usually more readable and slightly faster.
format() uses the same {} placeholders and the same format specifiers.
Example: Basic format()
price = 75
text = "The ticket price is {} rupees"
print(text.format(price))
Expected output:
The ticket price is 75 rupees
Example: Formatting Decimals
text = "Temperature: {:.1f}°C"
print(text.format(36.678))
Expected output:
Temperature: 36.7°C
Formatting Multiple Values
Empty placeholders are filled in order with the arguments passed to format().
items = 4
product_id = 210
cost = 349.5
order = "Order: {} items | ID: {} | Cost: {:.2f}"
print(order.format(items, product_id, cost))
Expected output:
Order: 4 items | ID: 210 | Cost: 349.50
Using Index Numbers
Numbers inside the placeholders refer to the position of the arguments, starting at 0. This lets you place values in any order.
order = "Item {1} costs {0:.2f} rupees"
print(order.format(499.99, "Headphones"))
Expected output:
Item Headphones costs 499.99 rupees
{1} takes the second argument ("Headphones"), and {0:.2f} takes the first (499.99) and formats it.
Reusing the Same Value
Index numbers also let you use a value more than once without passing it again.
age = 21
name = "Rahul"
info = "{1} is {0} years old. {1} is learning Python."
print(info.format(age, name))
Expected output:
Rahul is 21 years old. Rahul is learning Python.
Named Placeholders
Named placeholders make templates with many values easier to read.
details = "Car: {brand}, Model: {version}"
print(details.format(brand="Toyota", version="Corolla"))
Expected output:
Car: Toyota, Model: Corolla
F-Strings vs format()
| Feature | F-String | format() |
|---|---|---|
| Available since | Python 3.6 | Python 2.6 / 3.0 |
| Values appear | Directly inside the string | As arguments at the end |
| Readability | High | Lower with many values |
| Reusable templates | No — evaluated immediately | Yes — the template can be stored and reused |
| Recommended for | Most everyday formatting | Templates defined separately from their data |
Common Mistakes
| Mistake | Problem |
|---|---|
Forgetting the f prefix | The braces are printed literally: "Score: {score}" |
| Same quotes inside and outside (Python < 3.12) | SyntaxError; alternate " and ' |
Using .2f on a string | ValueError — format specifiers must match the value's type |
Mismatched counts in format() | IndexError when there are more placeholders than arguments |
| Expecting formatting to change the variable | Formatting only affects the displayed text |
Related Concepts
- Python Strings — string basics and concatenation
- Python Output — displaying text with
print() - Python Datetime — formatting dates with format codes, which also work in f-strings