Python f-strings are one of the most powerful and readable ways to format strings in Python. Introduced in Python 3.6, python f-strings — formally called formatted string literals — let you embed expressions directly inside string literals using a simple f prefix. If you've been using % formatting or str.format(), switching to f-string formatting will make your code cleaner, faster, and far easier to read. In this guide, you'll learn everything about f-string variables, f-string expressions, and how f-string formatting compares to older methods.
A python f-string is a string literal prefixed with f or F. Inside the string, you can place any valid Python expression inside curly braces {}, and Python evaluates it at runtime and inserts the result directly into the string.
name = "Hardik"
print(f"Hello, {name}!")
# Output: Hello, Hardik!
The {name} part is replaced by the value of the variable name. That's f-string variables at their simplest — no extra function calls, no index placeholders, just clean inline substitution.
Before python f-strings existed, developers used two older approaches. Understanding the difference helps you appreciate why f-string formatting is now the preferred choice.
% formatting (old style)language = "Python"
version = 3.6
print("Welcome to %s %s" % (language, version))
# Output: Welcome to Python 3.6
This works, but the syntax is verbose and error-prone, especially when dealing with multiple variables. The order of arguments must exactly match the placeholders.
str.format() (Python 3 style)city = "Vancouver"
country = "Canada"
print("City: {}, Country: {}".format(city, country))
# Output: City: Vancouver, Country: Canada
This is cleaner than % formatting, but still requires calling .format() and managing placeholders separately from the values. See the official str.format() documentation for full details.
city = "Vancouver"
country = "Canada"
print(f"City: {city}, Country: {country}")
# Output: City: Vancouver, Country: Canada
F-string formatting wins on every front — the variable names live right inside the string where they're used, making the code self-documenting and far less error-prone. Python evaluates the expressions lazily at the point of string creation, so there's no extra overhead from building intermediate objects.
Embedding f-string variables is the most common use case. You simply wrap any variable name in {} inside an f-string.
product = "Laptop"
price = 999
stock = 42
print(f"Product: {product} | Price: ${price} | In Stock: {stock} units")
# Output: Product: Laptop | Price: $999 | In Stock: 42 units
You can embed as many f-string variables as you need in a single string, and Python evaluates each one independently. Variables can be of any type — strings, integers, floats, lists, objects — Python automatically calls str() on the result to convert it into text.
class Book:
def __init__(self, title, author):
self.title = title
self.author = author
b = Book("Clean Code", "Robert Martin")
print(f"Reading '{b.title}' by {b.author}")
# Output: Reading 'Clean Code' by Robert Martin
Accessing attributes and properties of objects directly inside f-string variables is completely valid. This makes f-strings especially useful when working with data classes or ORM models.
Python f-strings go beyond simple variable substitution — you can place any valid Python expression inside the curly braces. This is what sets f-string expressions apart from older formatting methods.
width = 15
height = 8
print(f"Area of the rectangle: {width * height} sq units")
# Output: Area of the rectangle: 120 sq units
fruits = ["mango", "apple", "kiwi"]
print(f"Total fruits: {len(fruits)}, First: {fruits[0].upper()}")
# Output: Total fruits: 3, First: MANGO
temperature = 38
condition = "Hot" if temperature > 35 else "Comfortable"
print(f"Today's weather is: {condition}")
# Output: Today's weather is: Hot
student = {"name": "Priya", "grade": "A+"}
print(f"Student {student['name']} earned a grade of {student['grade']}")
# Output: Student Priya earned a grade of A+
Note the use of single quotes inside the f-string expression when the outer string uses double quotes — this avoids a syntax conflict.
F-string formatting supports a powerful format spec mini-language using a colon : inside the curly braces. This lets you control decimal places, padding, alignment, and number bases.
pi = 3.141592653589793
print(f"Pi rounded to 3 decimals: {pi:.3f}")
# Output: Pi rounded to 3 decimals: 3.142
The :.3f format spec means: display as a fixed-point float with 3 decimal places.
score = 47
total = 60
print(f"You scored {score/total:.1%} on the quiz")
# Output: You scored 78.3% on the quiz
annual_salary = 1250000
print(f"Annual Salary: ${annual_salary:,}")
# Output: Annual Salary: $1,250,000
items = [("Keyboard", 79), ("Mouse", 35), ("Monitor", 320)]
for item, cost in items:
print(f"{item:<12} ${cost:>6}")
# Output:
# Keyboard $ 79
# Mouse $ 35
# Monitor $ 320
:<12 means left-align within a field of width 12:>6 means right-align within a field of width 6This makes f-string formatting ideal for generating clean tabular output without any external libraries.
number = 255
print(f"Decimal: {number} | Binary: {number:b} | Hex: {number:x} | Octal: {number:o}")
# Output: Decimal: 255 | Binary: 11111111 | Hex: ff | Octal: 377
Full details on the format specification mini-language are available in the Python documentation.
When your string is long, you can split an f-string across multiple lines using parentheses or triple quotes.
user = "Anika"
role = "Admin"
access = "Full"
message = (
f"User: {user}\n"
f"Role: {role}\n"
f"Access Level: {access}"
)
print(message)
# Output:
# User: Anika
# Role: Admin
# Access Level: Full
item = "Notebook"
qty = 5
unit_price = 12.5
invoice = f"""
--- Invoice ---
Item : {item}
Quantity : {qty}
Unit Price: ${unit_price:.2f}
Total : ${qty * unit_price:.2f}
"""
print(invoice)
Output:
--- Invoice ---
Item : Notebook
Quantity : 5
Unit Price: $12.50
Total : $62.50
Triple-quoted f-strings are great for generating formatted reports, email templates, or SQL query strings.
Python allows f-string expressions to themselves contain f-strings or variables that determine the format spec — this is called nested f-strings.
decimal_places = 4
value = 2.718281828
print(f"Value: {value:.{decimal_places}f}")
# Output: Value: 2.7183
Here {decimal_places} inside the format spec dynamically sets how many decimal places to show. This is a powerful pattern when the formatting needs to change based on runtime conditions.
To include a literal { or } in an f-string, double them:
print(f"Use {{variable}} syntax in f-strings")
# Output: Use {variable} syntax in f-strings
You cannot use backslash escape sequences directly inside {} expressions in f-strings (prior to Python 3.12):
# This causes a SyntaxError in Python < 3.12
# print(f"{'hello\nworld'}")
# Workaround: define the value outside
text = "hello\nworld"
print(f"{text}")
Python 3.12 relaxed this restriction and now allows backslashes inside f-string expressions. Check the Python 3.12 release notes for details.
colors = {"sky": "blue", "grass": "green"}
# Use single quotes inside when the f-string uses double quotes
print(f"The sky is {colors['sky']}")
# Output: The sky is blue
This example brings together f-string variables, f-string expressions, and f-string formatting into a complete student report card generator.
# student_report.py
class Student:
def __init__(self, name, student_id, scores):
self.name = name
self.student_id = student_id
self.scores = scores # dict: {subject: score}
def average(self):
return sum(self.scores.values()) / len(self.scores)
def grade(self):
avg = self.average()
if avg >= 90:
return "A"
elif avg >= 75:
return "B"
elif avg >= 60:
return "C"
else:
return "F"
def generate_report(student):
separator = "-" * 40
header = f"{'STUDENT REPORT CARD':^40}"
print(separator)
print(header)
print(separator)
print(f"{'Name':<15}: {student.name}")
print(f"{'Student ID':<15}: {student.student_id}")
print(separator)
print(f"{'Subject':<20} {'Score':>10}")
print(separator)
for subject, score in student.scores.items():
status = "Pass" if score >= 50 else "Fail"
print(f"{subject:<20} {score:>8}/100 [{status}]")
print(separator)
print(f"{'Average Score':<20} {student.average():>8.1f}/100")
print(f"{'Final Grade':<20} {student.grade():>10}")
print(separator)
print(f"Result: {'Promoted to next level' if student.average() >= 50 else 'Needs improvement'}")
print(separator)
# --- Main ---
s = Student(
name="Rohan Mehta",
student_id="STU-2024-087",
scores={
"Mathematics": 88,
"Physics": 74,
"Chemistry": 91,
"English": 67,
"Computer Sci": 95
}
)
generate_report(s)
Output:
----------------------------------------
STUDENT REPORT CARD
----------------------------------------
Name : Rohan Mehta
Student ID : STU-2024-087
----------------------------------------
Subject Score
----------------------------------------
Mathematics 88/100 [Pass]
Physics 74/100 [Pass]
Chemistry 91/100 [Pass]
English 67/100 [Pass]
Computer Sci 95/100 [Pass]
----------------------------------------
Average Score 83.0/100
Final Grade B
----------------------------------------
Result: Promoted to next level
----------------------------------------
This example uses f-string variables to embed object attributes, f-string expressions for arithmetic and conditionals, and f-string formatting with alignment specifiers (:<, :>) and decimal control (:.1f) — all the key features covered in this guide working together in a realistic scenario.
For further reading, visit the official Python f-strings documentation.
Ready to go deeper? This guide is part of a complete Python tutorial series covering everything from basics to advanced topics. Whether you're just starting out or looking to sharpen your skills, the full series has you covered. Learn the full Python tutorial here.