Skip to content

Python f-strings Deep Dive

f-strings (formatted string literals, PEP 498, Python 3.6+) are the fastest and most readable way to build strings. Prefix a string with f and embed expressions in {}. This page goes deep into formatting; for the broader picture of %, .format(), and templates, see String Formatting.

quickstart.py
name = "Ada"
age = 36
print(f"{name} is {age}")          # Ada is 36
print(f"Next year: {age + 1}")     # Next year: 37  (any expression works)

Anything that evaluates to a value can go inside the braces — arithmetic, method calls, indexing, conditionals.

expressions.py
items = ["a", "b", "c"]
print(f"{len(items)} items")          # 3 items
print(f"upper: {'hi'.upper()}")       # upper: HI
print(f"first: {items[0]}")           # first: a
print(f"{'even' if 4 % 2 == 0 else 'odd'}")  # even

After a colon inside the braces comes a format spec that controls width, alignment, precision, and type. The general shape is:

spec.txt
{value:[fill][align][sign][width][,][.precision][type]}
precision.py
pi = 3.14159265
print(f"{pi:.2f}")     # 3.14    (2 decimal places)
print(f"{pi:.0f}")     # 3       (no decimals)
print(f"{1/3:.4f}")    # 0.3333
SpecMeaning
:<10Left-align in width 10.
:>10Right-align in width 10.
:^10Center in width 10.
:*^10Center, padding with *.
:08Zero-pad to width 8.
align.py
print(f"{'hi':<6}|")    # hi    |
print(f"{'hi':>6}|")    # |    hi  -> right aligned
print(f"{'hi':^6}|")    # |  hi  |
print(f"{42:08}")        # 00000042
print(f"{'x':*^7}")      # ***x***
numbers.py
print(f"{1000000:,}")        # 1,000,000
print(f"{1234.5:,.2f}")      # 1,234.50
print(f"{0.1234:.1%}")       # 12.3%   (percent with 1 decimal)
print(f"{255:#x}")           # 0xff    (hex with prefix)
TypeBase
:bBinary
:oOctal
:x / :XHex (lower/upper)
:eScientific notation
bases.py
n = 255
print(f"{n:b}")    # 11111111
print(f"{n:o}")    # 377
print(f"{n:x}")    # ff
print(f"{12345.678:.2e}")   # 1.23e+04

Add = inside the braces to print both the expression and its value — perfect for quick debugging.

debug.py
x = 10
y = 3
print(f"{x=}")          # x=10
print(f"{x + y=}")      # x + y=13
print(f"{x / y=:.2f}")  # x / y=3.33   (combine with a format spec)

Apply repr(), str(), or ascii() before formatting with !r, !s, !a.

conversions.py
name = "Ada"
print(f"{name!r}")    # 'Ada'   (repr -> shows quotes)
print(f"{name!s}")    # Ada     (str)

Braces can contain expressions that themselves come from variables — even the format spec.

nesting.py
value = 3.14159
places = 3
print(f"{value:.{places}f}")   # 3.142  (precision taken from a variable)
 
width = 10
print(f"{'hi':>{width}}")      # right-align in a width from a variable
multiline_escape.py
name, role = "Ada", "admin"
msg = (
    f"User: {name}\n"
    f"Role: {role}"
)
print(msg)
 
# To print literal braces, double them
print(f"{{not a placeholder}} but {name}")   # {not a placeholder} but Ada
sketch f-strings are the clearest, and only marginally the fastest p5.js
Four ways to build the same short string, measured a million times each. The popular claim that f-strings are dramatically faster does not survive contact with a benchmark: f-string, percent-formatting and plain concatenation land within four percent of each other. The one that is genuinely slower is str.format, at about 1.7 times the f-string. So choose f-strings because they read better and keep the values next to the text -- not because of the speed.
  • Forgetting the f"{x}" prints the braces literally; f"{x}" substitutes.
  • Literal braces need doubling{{ and }} to print { and }.
  • Quote clashes — don’t reuse the outer quote inside (or use the other quote): f"{d['key']}".
  • Heavy logic in braces hurts readability — compute first, then format.
  • f-strings embed any expression in {} and are the fastest, clearest way to format strings.
  • The format spec (:[fill][align][sign][width][,][.precision][type]) controls precision, padding, separators, and number bases.
  • {expr=} prints the expression and its value — handy for debugging.
  • Use !r/!s/!a for conversions, nest {...} for dynamic specs, and double {{ }} for literal braces.

pch.coffeeTagline

pch.coffeeCta

pch.feedbackHeading

pch.feedbackSubheading