Skip to content
Rochester, NY design, systems, study tools, and experiments Built in public

Python f-strings: formatting that reads like text

Formatted string literals (PEP 498, Python 3.6+) embed expressions inside string literals with `{expr}` syntax, with optional format specs after a colon. Faster and more readable than %-formatting or .format().

python python syntax formatting 2026-04-15

Python f-strings, introduced in Python 3.6 (PEP 498), are string literals prefixed with f (or F) that allow embedded expressions inside curly braces. They evaluate at runtime and format inline.

Basic usage

name = "Kevin"
count = 3
msg = f"{name} has {count} active sessions."
# 'Kevin has 3 active sessions.'

Anything between { and } is a Python expression — not just a variable name:

items = [1, 2, 3]
print(f"Total: {sum(items)}")          # Total: 6
print(f"Count: {len(items) * 2}")      # Count: 6

Format specifiers — after the colon

A : inside the braces introduces a format spec, identical to the one used by format():

pi = 3.14159265
f"{pi:.2f}"          # '3.14' — fixed-point, 2 decimal places
f"{pi:.4e}"          # '3.1416e+00' — scientific notation
f"{1234567:,}"       # '1,234,567' — thousands separators
f"{0.875:.1%}"       # '87.5%' — percent with 1 decimal
f"{'hi':>10}"        # '        hi' — right-aligned in 10 chars
f"{'hi':*^10}"       # '****hi****' — center-aligned, * fill

Self-documenting = (Python 3.8+)

Adding = after the expression prints both the expression text and its value — invaluable for debugging:

x = 42
y = 7
print(f"{x=}, {y=}, {x*y=}")
# x=42, y=7, x*y=294

Multi-line and triple-quoted

f-strings work with triple quotes for multi-line templates:

report = f"""
User: {user.name}
Last seen: {user.last_seen:%Y-%m-%d %H:%M}
Sessions: {user.session_count}
"""

When to avoid f-strings

  • Logging — use logger.info("User %s logged in", username) instead of logger.info(f"User {username} logged in"). The lazy %s style only formats if the log level is enabled; the f-string always evaluates.
  • SQL queries — never build SQL with f-strings (f"SELECT * FROM users WHERE id = {user_id}"). That's an injection vulnerability. Use parameterized queries with ? or %s placeholders.
  • User-facing strings that need translation — gettext can't extract f-string interpolations the way it can with _("Hello %(name)s").

Performance note

f-strings are typically faster than both "...".format(...) and "%s ..." % (...) because the interpreter compiles them to direct calls instead of running a format-spec parser at runtime. For hot loops generating lots of strings, prefer them.