f-string vs .format() vs % in Python: which should I use?

Short answer

Use f-strings for everything you write today. .format() is only worth reaching for when the template is stored separately from the values, and % formatting is legacy.

All three produce the same output:

python
name, count = "Dom", 15

f"{name} has {count} videos"           # f-string
"{} has {} videos".format(name, count) # .format()
"%s has %d videos" % (name, count)     # % formatting

f-strings win on every axis that matters: they are shorter, they are faster (the interpolation is compiled, not parsed at runtime), and the variable sits where it is used, so you read left to right instead of jumping to the argument list.

#When .format() is still right

When the template and the data are separated — a template loaded from a config file, a database, or a translation table:

python
TEMPLATES = {"welcome": "Hello {name}, you have {count} messages"}
TEMPLATES["welcome"].format(name="Dom", count=3)

You cannot use an f-string here, because an f-string is evaluated where it is written.

#Format specs work the same in both

python
f"{3.14159:.2f}"      # '3.14'
f"{1234567:,}"        # '1,234,567'
f"{0.256:.1%}"        # '25.6%'
f"{42:>8}"            # '      42'
f"{42:08.2f}"         # '00042.00'

#The debugging shortcut

An = inside the braces prints the expression and its value:

python
videos = 15
print(f"{videos=}")   # videos=15