What is an f-string in Python? Complete Guide

Discover f-strings in Python: syntax, practical examples, and best practices to efficiently format your strings.
9 min read
Believemy logo

F-strings, introduced with Python 3.6, represent a revolution in the way strings are formatted. They offer a clear, concise, and performant syntax that quickly won over the Python community. If you want to master this essential feature and many other Python concepts, our complete Python course will guide you through your learning journey.

 

Definition of f-strings

An f-string (formatted string literal) is a type of string in Python that allows you to embed Python expressions directly inside the string. The prefix f or F placed before the quotes tells the Python interpreter that it's an f-string.

The basic syntax is simple: you place your expressions between curly braces {} directly in the string. Python evaluates these expressions at runtime and inserts their result into the final string.

PYTHON
name = "Alice"
age = 28
message = f"Hello, my name is {name} and I'm {age} years old."
print(message)
# Result: Hello, my name is Alice and I'm 28 years old.

Before the appearance of f-strings, Python developers mainly used two methods to format strings:

  • The % operator (printf style)
  • The .format() method

F-strings surpass both approaches in terms of readability and performance.

 

Basic syntax and usage

Inserting variables

The most common use of f-strings is to insert variables into a string. You can use any variable defined in the current scope.

PYTHON
first_name = "Marie"
city = "Paris"
profession = "developer"

presentation = f"{first_name} lives in {city} and works as a {profession}."
print(presentation)
# Result: Marie lives in Paris and works as a developer.

 

Evaluating expressions

F-strings are not limited to simple variables. You can include any valid Python expression, including mathematical calculations, function calls, or methods.

PYTHON
# Mathematical calculations
width = 5
height = 3
print(f"The area of the rectangle is {width * height} m².")
# Result: The area of the rectangle is 15 m².

# Method calls
name = "python"
print(f"Language: {name.upper()}")
# Result: Language: PYTHON

# Function calls
import math
radius = 4
print(f"Circumference: {2 * math.pi * radius:.2f}")
# Result: Circumference: 25.13

 

Using with data structures

F-strings work perfectly with Python data structures like list, dict, and tuple.

PYTHON
# With a list
fruits = ["apple", "banana", "orange"]
print(f"My favorite fruit is {fruits[0]}.")
# Result: My favorite fruit is apple.

# With a dictionary
person = {"name": "Dupont", "age": 35}
print(f"{person['name']} is {person['age']} years old.")
# Result: Dupont is 35 years old.

# With a tuple
coordinates = (48.8566, 2.3522)
print(f"Paris is located at coordinates {coordinates[0]}, {coordinates[1]}.")
# Result: Paris is located at coordinates 48.8566, 2.3522.

 

Advanced f-string formatting

Format specifiers

F-strings support format specifiers after the : character in the expression. These specifiers allow you to precisely control the appearance of your data.

PYTHON
# Formatting decimal numbers
pi = 3.141592653589793
print(f"Pi rounded to 2 decimals: {pi:.2f}")
# Result: Pi rounded to 2 decimals: 3.14

print(f"Pi rounded to 4 decimals: {pi:.4f}")
# Result: Pi rounded to 4 decimals: 3.1416

# Scientific notation
large_number = 1234567890
print(f"Scientific notation: {large_number:.2e}")
# Result: Scientific notation: 1.23e+09

 

Alignment and padding

You can align text to the left, right, or center, and specify a fill character.

PYTHON
text = "Python"

# Left alignment (default for strings)
print(f"|{text:<15}|")
# Result: |Python         |

# Right alignment
print(f"|{text:>15}|")
# Result: |         Python|

# Center alignment
print(f"|{text:^15}|")
# Result: |    Python     |

# With a custom fill character
print(f"|{text:-^15}|")
# Result: |----Python-----|

 

Number formatting

F-strings offer many options to format numbers in a readable way.

PYTHON
# Thousand separator
amount = 1234567
print(f"Amount: {amount:,} €")
# Result: Amount: 1,234,567 €

# With underscore as separator (Python 3.6+)
print(f"Amount: {amount:_} €")
# Result: Amount: 1_234_567 €

# Percentage
ratio = 0.756
print(f"Success rate: {ratio:.1%}")
# Result: Success rate: 75.6%

# Numbers with sign
positive_value = 42
negative_value = -17
print(f"Positive: {positive_value:+d}, Negative: {negative_value:+d}")
# Result: Positive: +42, Negative: -17

 

Date formatting

F-strings integrate perfectly with the datetime module to format dates.

PYTHON
from datetime import datetime

now = datetime.now()

print(f"Date: {now:%d/%m/%Y}")
# Result: Date: 15/01/2025 (example)

print(f"Time: {now:%H:%M:%S}")
# Result: Time: 14:30:45 (example)

print(f"Full date: {now:%A %d %B %Y}")
# Result: Full date: Wednesday 15 January 2025 (example)

 

Advanced features

The = flag for debugging (Python 3.8+)

Since Python 3.8, you can use the = sign after an expression to display both the expression and its value. This feature is particularly useful for debugging.

PYTHON
x = 10
y = 20

print(f"{x=}")
# Result: x=10

print(f"{x=}, {y=}")
# Result: x=10, y=20

print(f"{x + y = }")
# Result: x + y = 30

# Combined with formatting
pi = 3.14159
print(f"{pi=:.2f}")
# Result: pi=3.14

 

Multi-line f-strings

You can create multi-line f-strings using triple quotes.

PYTHON
name = "Jean"
age = 30
city = "Lyon"

card = f"""
=============================
       PERSONAL CARD
=============================
Name   : {name}
Age    : {age} years
City   : {city}
=============================
"""

print(card)

 

Escaping curly braces

If you need to display literal curly braces in an f-string, you must double them.

PYTHON
variable = "value"

# To display literal curly braces
print(f"Here are curly braces: {{}}")
# Result: Here are curly braces: {}

print(f"JSON code: {{\"key\": \"{variable}\"}}")
# Result: JSON code: {"key": "value"}

 

Using with objects and classes

F-strings work with custom objects using the __str__ and __repr__ methods. You can use the !s and !r specifiers to force the use of one or the other method.

PYTHON
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def __str__(self):
        return f"{self.name} ({self.age} years old)"
    
    def __repr__(self):
        return f"Person(name='{self.name}', age={self.age})"

p = Person("Alice", 25)

# Using __str__ (default)
print(f"Person: {p}")
# Result: Person: Alice (25 years old)

# Force __str__
print(f"Person: {p!s}")
# Result: Person: Alice (25 years old)

# Force __repr__
print(f"Debug: {p!r}")
# Result: Debug: Person(name='Alice', age=25)

 

Comparison with other formatting methods

Here is a comparative table of the different string formatting methods in Python:

MethodSyntaxAdvantagesDisadvantages
f-stringf"Hello {name}"Readable, fast, flexiblePython 3.6+ only
.format()"Hello {}".format(name)Compatible Python 2.7+More verbose
% operator"Hello %s" % nameClassic styleLess flexible, obsolete
TemplateTemplate("Hello $name")Safe for user inputFewer features

In terms of performance, f-strings are generally faster than other methods because evaluation is done at compile time rather than at runtime.

PYTHON
import timeit

name = "Python"
version = 3.12

# Performance test
time_fstring = timeit.timeit('f"{name} {version}"', globals=globals(), number=1000000)
time_format = timeit.timeit('"{} {}".format(name, version)', globals=globals(), number=1000000)
time_percent = timeit.timeit('"%s %s" % (name, version)', globals=globals(), number=1000000)

print(f"f-string: {time_fstring:.3f}s")
print(f".format(): {time_format:.3f}s")
print(f"% operator: {time_percent:.3f}s")

 

Best practices

Good to know

F-strings are recommended by PEP 498 as the preferred formatting method for Python 3.6 and later versions. They improve code readability and reduce errors.

1. Prioritize readability

Avoid overly complex expressions in your f-strings. If the expression becomes difficult to read, assign it to a variable first.

PYTHON
# Avoid
print(f"Result: {[x**2 for x in range(10) if x % 2 == 0]}")

# Prefer
even_squares = [x**2 for x in range(10) if x % 2 == 0]
print(f"Result: {even_squares}")

 

2. Use f-strings for debugging

The = flag is your ally for quickly understanding the state of your variables. Also think about using the print function strategically to display your debug f-strings.

PYTHON
# Quick debugging
def calculate_price(quantity, unit_price, discount):
    print(f"{quantity=}, {unit_price=}, {discount=}")  # Debug
    total = quantity * unit_price * (1 - discount)
    print(f"{total=:.2f}")  # Debug
    return total

 

3. Document your functions with docstrings

Combine f-strings with docstring to create clear documentation and explicit error messages.

PYTHON
def divide(a, b):
    """Divides a by b and returns the result."""
    if b == 0:
        raise ValueError(f"Division impossible: {a} / {b} (division by zero)")
    return a / b

 

4. Be careful about security

Never use f-strings with unvalidated user input, as they can execute arbitrary code.

Warning

Never construct f-strings from strings coming from untrusted users. For these cases, use the string.Template class instead, which is more secure.

PYTHON
from string import Template

# For user input, prefer Template
user_input = "name"
template = Template("Hello $variable")
result = template.safe_substitute(variable=user_input)

 

5. Use f-strings for building SQL queries (with caution)

Never build SQL queries directly with f-strings. Always use the parameterization mechanisms of your database library.

PYTHON
# DANGER - NEVER DO THIS
user_name = "Alice"
query = f"SELECT * FROM users WHERE name = '{user_name}'"  # Vulnerable!

# CORRECT - Use parameters
cursor.execute("SELECT * FROM users WHERE name = ?", (user_name,))

 

Common use cases

Report generation

PYTHON
def generate_report(sales):
    total = sum(sales)
    average = total / len(sales) if sales else 0
    
    report = f"""
    ╔══════════════════════════════════╗
    ║         SALES REPORT             ║
    ╠══════════════════════════════════╣
    ║ Number of sales : {len(sales):>13} ║
    ║ Total           : {total:>13,.2f} € ║
    ║ Average         : {average:>13,.2f} € ║
    ╚══════════════════════════════════╝
    """
    return report

sales = [150.50, 200.00, 89.99, 450.00, 75.25]
print(generate_report(sales))

 

Logging and error messages

PYTHON
import logging

logging.basicConfig(level=logging.INFO)

def process_order(order_id, client, amount):
    logging.info(f"Processing order #{order_id} for {client} - Amount: {amount:.2f}€")
    
    try:
        # Processing...
        logging.info(f"Order #{order_id} processed successfully")
    except Exception as e:
        logging.error(f"Error order #{order_id}: {e}")

 

Building URLs and paths

PYTHON
from pathlib import Path

base_url = "https://api.example.com"
version = "v2"
resource = "users"
user_id = 12345

url = f"{base_url}/{version}/{resource}/{user_id}"
print(url)
# Result: https://api.example.com/v2/users/12345

# File paths
base_folder = Path("/home/user")
file_name = "report_2025"
extension = "pdf"
path = f"{base_folder}/{file_name}.{extension}"
print(path)
# Result: /home/user/report_2025.pdf

 

Frequently Asked Questions

Question

What is the difference between f-string and the .format() method?

F-strings are more readable and faster than the .format() method. With f-strings, you write variables directly in the string (f"Hello {name}"), while with .format(), you must pass them as arguments ("Hello {}".format(name)). F-strings are also evaluated at compile time, making them more performant. However, .format() remains useful for reusable templates or for compatibility with Python 2.7.

 

Question

Can you use f-strings with lambda functions?

Yes, you can call lambda functions in f-strings, but you must surround them with parentheses to avoid syntax errors with the : character.

PYTHON
# Correct
square = lambda x: x ** 2
print(f"The square of 5 is {square(5)}")
# Result: The square of 5 is 25

# With an inline lambda (parentheses required)
print(f"Result: {(lambda x: x * 2)(10)}")
# Result: Result: 20

 

Question

How to display curly braces in an f-string?

To display literal curly braces { and } in an f-string, you must double them. Use {{ to display an opening brace and }} for a closing brace. For example: f"Here are braces: {{value}}" will display Here are braces: {value} without interpreting value as an expression.

 

Question

How to learn to master f-strings and Python in general?

To master f-strings and the entire Python language, we recommend following our complete Python course on Believemy. This course will guide you step by step through all the essential concepts of the language, from basics to advanced features like f-strings, class, decorators, and much more. Regular practice with concrete exercises is the key to becoming an effective Python developer.

Related terms

Discover our python glossary

Browse the terms and definitions most commonly used in development with Python.

Share this article

Want to help us? Share this article on your networks or even better: on your site, in an article or in your newsletter.