An f-string puts a value inside braces and formats it after a colon. Start with the one-screen answer below. Then listen on for dates, dynamic widths, and the quote mistake that still breaks code on Python 3.11.
🎙️ Published & recorded: ·
Read every example as value, colon, format instruction. A dot followed by two and the letter f means two decimal places. A comma adds thousands separators. The percent format multiplies a ratio by one hundred and adds the percent sign. Alignment combines a direction symbol with a field width.
name, price, big, ratio = "Ada", 49.9, 1234567, 0.8756
f"{name}" # Ada basic
f"{price:.2f}" # 49.90 2 decimals ← most googled
f"{big:,}" # 1,234,567 thousands separator
f"{ratio:.1%}" # 87.6% percentage
f"{price:>10.2f}" # " 49.90" right-align, width 10
f"{name:<10}|" # "Ada |" left-align (tables!)
f"{name:^10}" # " Ada " centered
f"{42:05d}" # 00042 zero-padded
f"{255:x}" f"{255:b}" # ff / 11111111 hex, binary
f"{2+3}" # 5 any expression works
f"{price=}" # price=49.9 debug print (3.8+)
f"{{literal}}" # {literal} escaped braces
The equals-sign form is worth remembering for debugging because it prints both the expression and its value. Double braces when you need literal braces in the final text; a single brace belongs to the f-string parser.
Datetime objects accept date format codes directly after the colon. Year, month, and day make an ISO-style date; capital H and capital M make a twenty-four-hour time. If width or precision comes from a setting, put that variable in another pair of braces inside the format spec.
from datetime import datetime
now = datetime.now()
f"{now:%Y-%m-%d}" # 2026-07-25
f"{now:%H:%M}" # 14:30
f"{now:%b %d, %Y}" # Jul 25, 2026
f"{now:%A}" # Saturday
width, prec = 12, 3
f"{price:{width}.{prec}f}" # " 49.900"
Dynamic specs look crowded, so name the width and precision clearly. If the format is fixed, write the numbers directly. Indirection only helps when a caller or configuration actually changes them.
On Python 3.11 and older, using double quotes for both the outer f-string and a dictionary key can produce the real error, SyntaxError: f-string: unmatched left bracket. The parser thinks the inner quote ended the string. Keep the outer quotes double and change the key quotes to single. Python 3.12 relaxed this rule, but mixed quotes remain portable.
d = {"key": "value"}
f"{d["key"]}"
# SyntaxError: f-string: unmatched '['
f"{d['key']}" # value — works on Python 3.6+
python --version. If it is 3.11 or older, alternate the quote styles exactly as shown. If the error remains, inspect the previous line for an unclosed quote or brace; Python often points at the place where parsing finally became impossible, not where the typo began.Read percent formatting and dot format when maintaining old code, but write f-strings in new application code. Logging is the deliberate exception: logger calls keep percent placeholders so they can postpone building the message when that log level is disabled.
logger.info("price=%s", price) # keep this logging style
# Old code: "%0.2f" % price, or "{:.2f}".format(price)