Python String Formatting: A Practical Guide
String formatting lets Python programs combine values with readable text while controlling alignment, precision, numeric separators, dates, and other presentation details. Modern Python generally favors f-strings for application code.
1. F-Strings
Available since Python 3.6, f-strings embed expressions directly:
name = "Alice"
age = 30
message = f"{name} is {age} years old."
print(message)Expressions can be evaluated inside the braces:
width = 5
height = 3
print(f"Area: {width * height}")Keep embedded expressions reasonably small. Complex logic is easier to read when calculated before the f-string.
2. Format Numeric Precision
price = 19.9876
print(f"{price:.2f}") # 19.99Percentages:
ratio = 0.8734
print(f"{ratio:.1%}") # 87.3%Thousands separators:
population = 1_234_567
print(f"{population:,}")3. Alignment and Width
Left-align, right-align, or center text:
print(f"{'Name':<10} {'Age':>5}")
print(f"{'Alice':<10} {25:>5}")
print(f"{'Bob':<10} {30:>5}")Center a value:
print(f"{'Python':^20}")Use a fill character:
print(f"{'Title':-^20}")4. Integer Bases
number = 42
print(f"binary: {number:b}")
print(f"octal: {number:o}")
print(f"hex: {number:x}")Prefixes can be included with #:
print(f"{number:#x}") # 0x2a5. Debugging with =
Python 3.8+ supports a convenient debugging form:
name = "Alice"
age = 30
print(f"{name=}, {age=}")This prints both the expression and its representation.
6. !s and !r
Choose string or representation conversion explicitly:
value = "hello\nworld"
print(f"{value!s}")
print(f"{value!r}")!r is particularly useful for debugging because escape characters and quotes remain visible.
7. str.format()
Older code frequently uses str.format():
message = "{} is {} years old.".format("Alice", 30)Named fields can improve clarity:
message = "{name} is {age} years old.".format(name="Alice", age=30)str.format() remains supported and can be useful when the format string comes from a source that should not contain arbitrary Python expressions.
8. Old % Formatting
Legacy Python code may contain:
name = "Alice"
age = 30
print("%s is %d years old." % (name, age))This style is still used by some APIs, notably the standard logging module, where deferred % formatting is intentional:
import logging
logging.info("User %s logged in", name)For ordinary new string construction, f-strings are usually clearer.
9. Dates and Times
datetime objects support format specifications:
from datetime import datetime
now = datetime(2026, 9, 1, 10, 30)
print(f"{now:%Y-%m-%d %H:%M}")10. Do Not Build SQL with String Formatting
Avoid constructing SQL queries with f-strings or other formatting methods using untrusted values:
# Avoid this:
# query = f"SELECT * FROM users WHERE name = '{name}'"Use the parameter mechanism provided by the database driver instead. The same principle applies to shell commands and other contexts where quoting and injection matter.
Conclusion
F-strings are the best default for most modern Python formatting. Learn the format-specification mini-language for precision, alignment, and numeric presentation, keep complex logic outside the string, and use specialized parameter APIs instead of formatting untrusted data into SQL or shell commands.