How to use f-strings in Python

Master Python f-strings. This guide covers different methods, tips and tricks, real-world applications, and how to debug common errors.

How to use f-strings in Python
Published on: 
Fri
Feb 13, 2026
Updated on: 
Tue
Feb 24, 2026
The Replit Team Logo Image
The Replit Team

Python's f-strings offer a modern, readable way to format strings. They embed expressions inside string literals, which creates a clean syntax and simplifies complex string manipulations.

Here, you'll find essential techniques, practical tips, and real-world applications. The content also includes debugging advice to help you master this powerful feature for your projects.

Basic f-string usage

name = "Python"
message = f"Hello, {name}!"
print(message)--OUTPUT--Hello, Python!

The f prefix before the opening quote is what activates the f-string functionality. It signals to Python that any expressions inside curly braces {} should be evaluated at runtime and inserted into the string's final output.

This makes the code more intuitive. Instead of juggling placeholders and arguments like you would with str.format() or the % operator, the variable name is placed exactly where its value will appear. This direct embedding keeps your formatting logic and layout tightly coupled, improving readability.

Common f-string techniques

The core technique involves placing variables inside {}, but you can also add formatting specifiers for numbers or embed entire expressions for evaluation.

Inserting variables with {}

first_name = "Ada"
last_name = "Lovelace"
greeting = f"Welcome, {first_name} {last_name}!"
print(greeting)--OUTPUT--Welcome, Ada Lovelace!

The most direct way to use f-strings is by embedding variables. In the example, both {first_name} and {last_name} are evaluated and their values are inserted into the greeting string. This avoids manual string concatenation with the + operator, making the code cleaner and more readable.

  • You can include any number of variable expressions inside a single f-string.
  • The expressions are evaluated at runtime, so their current values are always used.
  • Any text outside the braces, like the space between the names, is included as a literal part of the string.

Formatting numbers with precision specifiers

value = 12345.6789
print(f"Rounded to 2 decimal places: {value:.2f}")
print(f"With commas: {value:,.2f}")
print(f"Scientific notation: {value:.2e}")--OUTPUT--Rounded to 2 decimal places: 12345.68
With commas: 12,345.68
Scientific notation: 1.23e+04

You can format numbers directly within an f-string by adding a colon (:) followed by a format specifier. This powerful feature lets you control numerical presentation without needing separate functions, making your code cleaner.

  • Use :.2f to round a number to two decimal places for fixed-point notation.
  • Including a comma, as in :,.2f, automatically adds thousands separators.
  • The :.2e specifier formats the number in scientific notation.

Using expressions inside {}

x = 10
y = 5
print(f"{x} + {y} = {x + y}")
print(f"{x} × {y} = {x * y}")
print(f"Is {x} greater than {y}? {x > y}")--OUTPUT--10 + 5 = 15
10 × 5 = 50
Is 10 greater than 5? True

F-strings aren't just for variables; you can embed any valid Python expression directly inside the curly braces. The expression is evaluated at runtime, and its result is formatted into the string. This allows you to perform calculations or comparisons on the fly, making your code more dynamic.

  • The expression {x + y} calculates the sum before inserting it.
  • Similarly, {x * y} computes the product.
  • You can even evaluate boolean expressions like {x > y}, which returns True or False.

Advanced f-string features

Building on the common techniques, f-strings also give you advanced control over alignment, data access, and even debugging with the handy = specifier.

Alignment and padding with format specifiers

names = ["Alice", "Bob", "Charlie"]
for name in names:
print(f"{name:>10} | {name:<10} | {name:^10}")--OUTPUT--Alice | Alice | Alice
Bob | Bob | Bob
Charlie | Charlie | Charlie

F-strings give you precise control over text alignment, which is perfect for creating well-formatted tables or reports. By adding a format specifier after the variable, you can define the total width and how the text should be positioned within that space.

  • Use :>10 to right-align text within a 10-character field.
  • Use :<10 for left-alignment, which is often the default for strings.
  • Use :^10 to center the text perfectly within the allocated space.

Working with dictionaries and objects

data = {"name": "Alice", "age": 30}
print(f"Name: {data['name']}, Age: {data['age']}")

class Person:
def __init__(self, name):
self.name = name

print(f"Person: {Person('Bob').name}")--OUTPUT--Name: Alice, Age: 30
Person: Bob

F-strings let you access dictionary values and object attributes directly within the curly braces. This keeps your code concise by avoiding the need for temporary variables. You can embed complex expressions, making your string formatting both powerful and readable.

  • For dictionaries, you can use key lookups like data['name']. Just be sure to use different quotes than your f-string's outer quotes to avoid syntax errors.
  • For objects, standard dot notation like Person('Bob').name works seamlessly to access attributes on the fly.

Debugging with the = specifier

radius = 5
area = 3.14159 * radius**2
print(f"{radius=}, {area=:.2f}")--OUTPUT--radius=5, area=78.54

The = specifier is a fantastic shortcut for debugging. It automatically displays both the variable’s name and its value, making it easy to inspect your code’s state at runtime. This saves you from typing out longer print statements like f"radius = {radius}".

  • As shown with {area=:.2f}, you can combine the = specifier with other formatting options.
  • This feature is perfect for quickly checking the values of variables without interrupting your workflow.

Move faster with Replit

Replit is an AI-powered development platform that transforms natural language into working applications. You can describe what you want to build, and Replit Agent creates it—complete with databases, APIs, and deployment.

The f-string techniques from this article can be turned into production-ready tools with Replit Agent. For example, you could build:

  • A financial calculator that uses precision specifiers like :.2f to correctly format currency.
  • A command-line tool that generates neatly formatted reports by applying alignment and padding to text.
  • A unit converter that performs calculations on the fly and displays the results directly in the output string.

Turn your concept into a working application. Describe your idea, and Replit Agent will write, test, and deploy the code for you.

Common errors and challenges

While f-strings are powerful, a few common pitfalls can trip you up, from simple syntax mistakes to more subtle type-related errors.

  • Forgetting the f prefix: It’s a simple mistake, but leaving out the f means your expressions won't be evaluated. Instead of seeing a variable's value, you'll just see the literal curly braces and the variable name in your string.
  • Escaping curly braces: If you need to include literal curly braces in your output, you can't just type {}. You must double them up like this: {{ and }}. This tells Python to treat them as characters, not as placeholders for an expression.
  • Type errors when formatting: Applying a format specifier that doesn't match the data type will raise a ValueError. For example, you can't use a numeric format specifier like :.2f on a string, as Python won't know how to perform the conversion.

Forgetting the f prefix when creating formatted strings

This is a simple but frequent mistake. When you leave out the f before the opening quote, Python treats the string literally. The expressions inside the curly braces won't be evaluated, leaving them as plain text in the output. The code below shows this in action.

name = "Python"
message = "Hello, {name}!" # Missing f prefix
print(message)

The output is Hello, {name}! because the string is treated as a literal. Without the f prefix, Python doesn't evaluate the expression inside the braces. The corrected code below shows how to fix this.

name = "Python"
message = f"Hello, {name}!" # Added f prefix
print(message)

Adding the f prefix turns the string into a proper f-string, allowing Python to evaluate the {name} expression. The output is now the intended result: Hello, Python! It's a simple fix that's easy to overlook, especially when you're coding quickly or refactoring old code. If you ever see literal curly braces in your output, the missing f is the most likely culprit.

Escaping curly braces in f-strings

What if you need to print literal curly braces within an f-string? Python treats them as expression placeholders, which can cause a NameError if the content isn't a variable. The following code illustrates what happens when you try this directly.

value = 42
template = f"The value is {value} in {brackets}" # Will try to substitute {brackets}
print(template)

The code fails because the f-string attempts to evaluate {brackets} as an expression, but brackets is an undefined variable, which raises a NameError. The following example shows the correct approach to get the intended output.

value = 42
template = f"The value is {value} in {{brackets}}" # Double braces to escape them
print(template)

To include literal curly braces in an f-string, you must escape them by doubling them up, like {{ and }}. This signals to Python that they aren't placeholders for expressions. This technique is crucial when you're generating text that requires literal braces, such as JSON templates or code snippets. Without escaping, Python will try to evaluate the content inside the braces, which can lead to an error if it's not a valid expression.

Type errors when formatting numeric values in f-strings

You'll get a TypeError if you try to apply a numeric format specifier, like :.2f, to a string. Python can't format a value as a number if it isn't one, a common issue with external data. The code below shows this error in action.

value = "123.456" # String value
formatted = f"Amount: ${value:.2f}" # Will raise TypeError
print(formatted)

The :.2f specifier requires a number, but the value variable is a string. This type mismatch is what triggers the TypeError. The following example demonstrates the correct way to handle this.

value = "123.456" # String value
formatted = f"Amount: ${float(value):.2f}" # Convert to float first
print(formatted)

To fix the TypeError, you must convert the string to a number before formatting. The expression float(value) turns the string into a floating-point number, allowing the :.2f specifier to correctly round it. This error is common when you're processing data from external sources like APIs or user input, since that data often arrives as text. Always ensure your data types match your formatting rules to avoid unexpected crashes.

Real-world applications

With the fundamentals and common errors covered, you can apply f-strings to practical tasks like formatting log entries and generating HTML content.

Formatting log entries with timestamps

F-strings are ideal for creating structured log messages because you can format datetime objects directly inside the string.

from datetime import datetime

timestamp = datetime.now()
user_id = 12345
action = "login"
log_entry = f"[{timestamp:%Y-%m-%d %H:%M:%S}] User {user_id} performed {action}"
print(log_entry)

This code leverages f-strings to format a datetime object on the fly. The expression {timestamp:%Y-%m-%d %H:%M:%S} uses a format string after the colon to dictate the timestamp's appearance, similar to the strftime() method. This approach integrates formatting directly into the string itself.

  • The format string uses codes like %Y for year and %H for hour to build a custom layout.
  • Other variables like user_id and action are embedded alongside it, producing a complete, structured message in one line.

Generating HTML content with f-strings

F-strings make it simple to generate dynamic HTML by embedding data directly into your markup, which is perfect for tasks like creating a table from a list.

data = [
{"name": "Alice", "age": 28, "role": "Developer"},
{"name": "Bob", "age": 35, "role": "Manager"},
{"name": "Charlie", "age": 24, "role": "Designer"}
]

html = "<table>\n <tr><th>Name</th><th>Age</th><th>Role</th></tr>"
for person in data:
html += f"\n <tr><td>{person['name']}</td><td>{person['age']}</td><td>{person['role']}</td></tr>"
html += "\n</table>"

print(html)

This code dynamically generates an HTML table from a list of dictionaries. It starts with a basic table structure and then iterates through the data list using a for loop to build the table's body.

  • Inside the loop, an f-string creates a new table row (<tr>) for each person.
  • Expressions like {person['name']} access dictionary values directly, embedding them into the table cells (<td>).
  • The += operator appends each completed row to the main html string, building the final table piece by piece.

Get started with Replit

Turn your f-string skills into a real tool. Tell Replit Agent to “build a currency converter with formatted output” or “create a log file parser that generates a neatly aligned report.”

The agent writes the code, tests for errors, and deploys the app, letting you focus on your idea. Start building with Replit and see your project come to life.

Get started free

Create and deploy websites, automations, internal tools, data pipelines and more in any programming language without setup, downloads or extra tools. All in a single cloud workspace with AI built in.

Get started for free

Create & deploy websites, automations, internal tools, data pipelines and more in any programming language without setup, downloads or extra tools. All in a single cloud workspace with AI built in.