Nested f-strings in Python

โฑ๏ธ 4 min read ๐Ÿ Python

On Python 3.11 and earlier, an f-string raises SyntaxError when an expression inside its braces reuses the outer quote character, so write f"{data['name']}" instead of f"{data["name"]}". Python 3.12 and newer (PEP 701) accept the same quotes and backslashes inside the braces, but a backslash-escaped quote such as \" in an expression is still a SyntaxError on every version. The other kind of nesting, a field inside the format spec like f"{value:.{n}f}", makes precision, width, or fill dynamic.

Quick answer: To fix a nested-quote SyntaxError on Python 3.11 or earlier, switch quote styles inside the braces (f"{data['name']}") and move any backslash out of the expression into a variable. On Python 3.12+, reusing the same quotes works: f"{data["name"]}". On every version, never escape quotes with a backslash inside the braces. To make precision dynamic, nest a field in the spec: f"{value:.{n}f}".

What Is a Nested f-string in Python?

A nested f-string is an f-string with a second replacement field or a second f-string inside its curly braces. The common form computes the format spec at runtime, as in f"{value:.{n}f}"; the rarer form uses a literal f-string as the expression, as in f"{f'inner {x}'}", and that form, like any quoted string inside the braces such as a dict key, must not reuse the outer quote character on Python 3.11 and earlier.

How Do You Set Decimal Places with a Variable in an f-string?

Put the variable in its own braces inside the format spec: f"{value:.{n}f}" formats value with n decimal places. Python evaluates the inner field first, so with n = 2 the spec becomes .2f before it is applied.

value = 3.14159265359

for n in range(1, 5):
    print(f"{value:.{n}f}")
# 3.1
# 3.14
# 3.142
# 3.1416

How Do You Set f-string Width or Padding with a Variable?

Nest the width variable inside the alignment spec: f"{name:<{width}}" left-aligns name in a field width characters wide, padded with spaces. Compute the width once, for example from the longest value, to line up a column of text.

names = ["Alice", "Bob", "Charlie"]
width = max(len(n) for n in names)  # 7

for n in names:
    print(f"{n:<{width}} | done")
# Alice   | done
# Bob     | done
# Charlie | done

Dynamic Fill Character

The fill character can come from a variable too. It goes right before the alignment character (<, ^, or >).

fill = "*"
title = "REPORT"

f"{title:{fill}^20}"
# '*******REPORT*******'

Conditional Formatting Inside an f-string

Use a ternary expression โ€” this isn't truly "nested," but it's the second-most-common reason people search for nested f-strings.

change = -0.042

f"{('โ–ผ' if change < 0 else 'โ–ฒ')} {abs(change):.1%}"
# 'โ–ผ 4.2%'

# Conditional precision:
n = 0
f"{value:.{2 if n == 0 else n}f}"  # '3.14' when n is 0

The Quote Rule (Python 3.11 and Earlier)

Before Python 3.12 you could not reuse the same quote character inside an f-string expression. The tokenizer read the whole f-string as one string literal, so a matching quote inside the braces ended the string early. This forces you to alternate quote styles:

# Python 3.11 โ€” must use the OTHER quote inside braces:
data = {"name": "Alice"}
f"{data['name']}"      # OK โ€” single quotes inside double-quoted f-string
# f"{data["name"]}"    # 3.11: SyntaxError: f-string: unmatched '['

# To nest f-strings, alternate:
inner = "world"
f"hello {f'{inner}!'}"  # 'hello world!'
# f"hello {f"{inner}!"}"  # 3.11: SyntaxError: f-string: expecting '}'

Python 3.12+ Relaxed the Quote Rule (PEP 701)

PEP 701 formalized f-strings in Python's grammar in 3.12, which lifted the quote and backslash restrictions on the expressions inside the braces.

# Python 3.12+ โ€” same quotes are fine:
data = {"name": "Alice"}
f"{data["name"]}"   # 'Alice'  (would error pre-3.12)

# You can also nest f-strings with the same quotes:
f"hello {f"{inner}!"}"   # 'hello world!' on 3.12+

# And backslashes are allowed in expressions:
items = ["a", "b"]
f"{'\n'.join(items)}"   # OK on 3.12+, SyntaxError before

When to Use a Nested f-string vs format()

If the format spec is fully dynamic and reused, str.format() is often clearer:

spec = ".2f"
value = 3.14159

# Nested f-string:
f"{value:{spec}}"          # '3.14'

# format() โ€” same result, sometimes cleaner:
"{:{}}".format(value, spec) # '3.14'

# format_map for many fields:
"{value:{spec}}".format_map({"value": value, "spec": spec})

Common Pitfalls

Most nested f-string errors come from quotes, backslashes, or nesting too deeply.

Pro Tip: Check your Python version with python --version. If you're on 3.12 or newer, the PEP 701 relaxation means most "nested f-string is a SyntaxError" advice on Stack Overflow is outdated. Backslash-escaped quotes inside the braces still fail, though; see Common Pitfalls above.

โ† Back to Python Tips