Python F-Strings: Syntax, Examples, and Formatting
Table of Contents
Python f-strings insert variables and expressions directly into text dynamically. Just put an f before the opening quote, and each value inside curly braces:
player_name = "Boots"
level = 7
message = f"{player_name} is level {level}."
print(message)
# Boots is level 7.
BTW, you can run every example in Boot.dev's free Python playground. If variables and basic data types are still new to you, start with Learn Python for Beginners and come back after its "Variables" chapter.
What Is an F-String in Python?
Have you ever played old-school Pokemon and chosen a funny name so that the in-game messages would come out weird?
An f-string, short for formatted string literal, creates a string while inserting dynamic values into it. Python added the syntax in version 3.6 via PEP 498.
num_bananas = 10
bananas = f"You have {num_bananas} bananas"
print(bananas)
# You have 10 bananas
- Add an
fto the start of the quotes - Put a variable or expression inside
{}to interpolate its value into the string
You can assign an f-string to a variable, return it from a function, or put it directly inside print(). It's just a string.
How Do You Put Variables in an F-String?
Write the variable name between curly braces. Python evaluates the f-string when that line runs and converts the value to text:
name = "Yarl"
race = "dwarf"
age = 37
description = f"{name} is a {race} who is {age} years old."
print(description)
# Yarl is a dwarf who is 37 years old.
The braces are replacement fields. Each field can contain any valid Python expression, not just a variable name.
Can Python F-Strings Contain Expressions?
Yes. Arithmetic, function calls, method calls, indexing, and conditional expressions all work inside an f-string:
first_name = "boots"
completed_quests = 8
total_quests = 10
report = f"{first_name.title()} completed {completed_quests / total_quests:.0%} of the quests."
print(report)
# Boots completed 80% of the quests.
I like to keep complicated logic outside the string... this is kinda nasty:
strength = 10
weapon_power = 3
armor = 7
print(f"Damage: {(strength * weapon_power) - armor}")
# Damage: 23
But a named variable is easier to read and debug:
strength = 10
weapon_power = 3
armor = 7
damage = (strength * weapon_power) - armor
print(f"Damage: {damage}")
# Damage: 23
F-strings make formatting more readable. Stuffing a small program between the braces... doesn't.
How Do F-String Format Specifiers Work?
Put a colon after the expression to add a format specifier. The specifier controls precision, separators, signs, padding, alignment, percentages, and several other display details.
Format Decimals, Commas, and Percentages
These are the number formats you'll use most often:
| Goal | F-string | Result |
|---|---|---|
| Two decimal places | f"{price:.2f}" |
"1234.50" |
| Comma thousands separator | f"{price:,.2f}" |
"1,234.50" |
| Percentage | f"{ratio:.1%}" |
"87.5%" |
| Four-digit zero padding | f"{file_number:04d}" |
"0042" |
| Always show a sign | f"{change:+d}" |
"+12" |
price = 1234.5
ratio = 0.875
file_number = 42
change = 12
print(f"Price: ${price:,.2f}")
print(f"Progress: {ratio:.1%}")
print(f"Save file: {file_number:04d}")
print(f"Health change: {change:+d}")
The precision in .2f means two digits after the decimal point. The % format multiplies the value by 100 and adds the percent sign, so 0.875 becomes 87.5% with .1%.
Add Padding and Alignment
A width sets the minimum number of characters. Add <, >, or ^ to align the value left, right, or center:
name = "Boots"
print(f"|{name:<10}|")
print(f"|{name:>10}|")
print(f"|{name:^10}|")
|Boots |
| Boots|
| Boots |
Replace the empty space with another fill character by putting it before the alignment symbol:
name = "Boots"
print(f"{name:.^10}")
# ..Boots...
Format Dates
Date and time objects understand their own %-based format codes inside an f-string:
from datetime import date
launch_day = date(2026, 8, 24)
print(f"Launch day: {launch_day:%B %d, %Y}")
# Launch day: August 24, 2026
The datetime format code reference lists the available year, month, day, and time fields.
How Do You Debug With F-Strings?
Python 3.8 which is old enough that you should be able to forget about anything that came before added the = debug syntax. It prints both an expression and its value:
damage = 12
armor = 5
print(f"{damage=}, {armor=}")
# damage=12, armor=5
You can combine it with a format specifier:
accuracy = 0.936
print(f"{accuracy=:.1%}")
# accuracy=93.6%
This is fantastic for quick debugging! But get rid of the print once you've found the bug unless the output is useful to someone other than you...
How Do You Escape Curly Braces in an F-String?
Double a brace when you want the brace itself to appear in the result:
name = "Boots"
message = f"Write {{name}} to show a placeholder. The value is {name}."
print(message)
# Write {name} to show a placeholder. The value is Boots.
Use {{ for a literal opening brace and }} for a literal closing brace. A single unmatched brace causes a SyntaxError.
How Do Quotes and Multiline F-Strings Work?
Quotes work normally as long as Python can tell where the string starts and ends. Switching the quote style inside a replacement field keeps dictionary lookups readable:
player = {"name": "Boots"}
message = f"Welcome, {player['name']}!"
Use triple quotes for a multiline f-string:
name = "Boots"
quest = "Fix the API"
report = f"""Player: {name}
Quest: {quest}"""
F-Strings vs. str.format() and Concatenation
All three approaches below produce the same text:
name = "Boots"
level = 7
with_f_string = f"{name} is level {level}."
with_format = "{} is level {}.".format(name, level)
with_concatenation = name + " is level " + str(level) + "."
I recommend using the f-string by default. It keeps each value beside the text that describes it and handles non-string values without manual str() calls.
str.format() still earns its keep when you need to select or reuse a template before supplying values:
template = "{name} is level {level}."
message = template.format(name="Boots", level=7)
F-strings are evaluated immediately, so they aren't reusable templates. Old % formatting still appears in legacy Python and the logging module, but there's little reason to choose it for ordinary new strings.
Common Python F-String Mistakes
Forgetting the f
Without the prefix, Python treats the braces as ordinary characters:
name = "Boots"
print("Hello, {name}!")
# Hello, {name}!
Using Empty Braces
Unlike str.format(), an f-string needs a Python expression inside every replacement field. f"Hello, {}" is invalid.
Mismatching Braces or Quotes
Every opening brace and quote needs a matching closing character. If the expression contains a string or dictionary key, switching between single and double quotes is usually cleaner than escaping everything.
Expecting a Template
An f-string stores the value from the moment it is evaluated:
level = 7
message = f"Level: {level}"
level = 8
print(message)
# Level: 7
Build a new f-string after the value changes, or use str.format() when you need a reusable template.
F-strings are the normal way to put values into text in modern Python. Start with variables and expressions, then reach for format specifiers only when the output needs precision, padding, alignment, or another deliberate display rule. The Learn Python for Beginners course teaches f-strings in context and gives you an executable exercise instead of another wall of syntax.
Frequently Asked Questions
What does the f before a string mean in Python?
The f marks a formatted string literal, usually called an f-string. Python evaluates expressions inside curly braces and inserts their values into the string.
How do you format a number to two decimal places in a Python f-string?
Put :.2f after the expression inside the curly braces. For example, f"{price:.2f}" formats the value of price with two digits after the decimal point.
How do you print literal curly braces in a Python f-string?
Double each brace. Write {{ to produce an opening brace and }} to produce a closing brace.
Are f-strings better than str.format() in Python?
F-strings are usually the clearest choice when the values are available as you create the string. str.format() remains useful when you need to choose or reuse a template before supplying its values.
