Maintenance

Site is under maintenance — quizzes are still available.

Go to quizzes

Format Strings in Python

Learn to format strings using f-strings and format() in Python. This step-by-step tutorial covers core concepts, hands-on exercises, troubleshooting, and what to study next.

Focus: format strings with f-strings and format()

Sponsored

You’ve written Python code that prints variables — maybe with clunky string concatenation like name + ' is ' + str(age) + ' years old'. That works, but it’s error-prone, hard to read, and slow to write. Worse, when you try to insert floats, dates, or formatted numbers, the code explodes into a mess of str() calls and plus signs. Python’s f-strings and the .format() method solve this cleanly — letting you embed expressions directly inside strings, control alignment, pad with spaces or zeros, and format numbers with currency symbols or decimal places — all in one readable line.

The problem this lesson solves

Imagine you’re building a financial dashboard. You need to display account balances with two decimal places, right-aligned in a table, with a dollar sign. Without proper string formatting, you’d write something like:

balance = 1234.5
print("$" + str(round(balance, 2)).ljust(10))

Fragile, right? Miss a parenthesis or forget ljust() and your columns won’t line up. The real pain surfaces when you need:

  • Dynamic content — variables, expressions, function calls inside strings
  • Precision control — rounding decimals, padding numbers
  • Alignment — left, right, center for tabular output
  • Readability — one clear line vs. a spaghetti of concatenation

The format strings with f-strings and format() technique eliminates all that friction.

Core concept / mental model

Think of a format string as a template with placeholders — like fill-in-the-blank mad libs. You define the skeleton text, then inject specific values into the blanks.

  • f-strings (Python 3.6+) let you write f"Hello, {name}!". The f prefix tells Python to evaluate anything inside {} as an expression and insert its string representation.
  • .format() method uses the same curly-brace syntax but without the f prefix: "Hello, {}".format(name).

Both produce the same result. The mental model is simple: write string → mark insertion points with {} → provide the values. The work happens at runtime when Python evaluates those curly braces.

Pro tip: F-strings are faster than .format() for most cases because they’re evaluated at compile time when possible. .format() is more flexible for dynamic templates (like reading a format string from a config file).

How it works step by step

1. Basic variable insertion

name = "Alice"
age = 30
# f-string
print(f"{name} is {age} years old.")
# .format()
print("{} is {} years old.".format(name, age))

Output:

Alice is 30 years old.
Alice is 30 years old.

2. Expressions and calculations

You can put any expression inside {} — arithmetic, function calls, even inline conditionals:

price = 19.99
tax_rate = 0.08
print(f"Total with tax: ${price * (1 + tax_rate):.2f}")

Output:

Total with tax: $21.59

The :.2f after the colon is a format specifier2 decimal places, f for fixed-point float.

3. Named placeholders with .format()

Use {name} instead of {} for clarity, especially with many values:

person = {"name": "Bob", "job": "engineer"}
print("{name} works as a {job}.".format(**person))

Output:

Bob works as an engineer.

4. Format specifiers: padding, alignment, numeric types

The format mini-language uses : followed by: - Alignment: < (left), > (right), ^ (center) - Width: number of characters - Fill character: optional character before alignment, e.g. 0 for zero-padding - Type: d (integer), f (float), x (hex), % (percentage)

value = 42
print(f"|{value:>5}|")    # right-aligned, width 5
print(f"|{value:0>5}|")   # zero-padded
print(f"|{value:<5}|")    # left-aligned
print(f"|{value:^5}|")    # centered

Output:

|   42|
|00042|
|42   |
| 42  |

Hands-on walkthrough

Let’s build a simple inventory report for a bookstore. We’ll use both f-strings and .format() to format prices, quantities, and totals.

Example 1: Basic f-string report

items = [
    ("Python 101", 2, 39.99),
    ("Data Science Handbook", 5, 59.99),
    ("Machine Learning for Beginners", 1, 89.99)
]

print("Inventory Report")
print("=" * 50)
for name, qty, price in items:
    total = qty * price
    print(f"{name:35s} {qty:3d} @ ${price:6.2f} = ${total:7.2f}")

Output:

Inventory Report
==================================================
Python 101                          2 @ $ 39.99 = $  79.98
Data Science Handbook                5 @ $ 59.99 = $ 299.95
Machine Learning for Beginners       1 @ $ 89.99 = $  89.99

Example 2: Named placeholders with .format()

template = "{book:30s} | {qty:3d} units | ${price:6.2f} each"
for name, qty, price in items:
    print(template.format(book=name, qty=qty, price=price))

Output:

Python 101                    |   2 units | $ 39.99 each
Data Science Handbook         |   5 units | $ 59.99 each
Machine Learning for Beginners|   1 units | $ 89.99 each

Example 3: Dynamic template from a configuration

Sometimes you need to load format strings from a file or database. .format() shines here:

# config could come from a JSON file
config_format = "{name:>20s} {age:>3d}"
users = [("Alice", 30), ("Bob", 25), ("Charlie", 35)]

for name, age in users:
    print(config_format.format(name=name, age=age))

Output:

              Alice  30
                Bob  25
            Charlie  35

Compare options / when to choose what

Method When to use Example
f-string Static templates — you control the string at write time f"Hello, {name}!"
.format() Dynamic templates — format string comes from a variable or config "Hello, {}".format(name)
% formatting Legacy code (pre‑Python 2.6) "%s is %d" % (name, age)
string.Template Simple substitution with $ syntax, safe for user-provided templates Template("$name is $age").substitute(...)

Recommendation: Default to f-strings for new code. Use .format() when you need to separate the template (e.g., loadable from files). Avoid % formatting unless maintaining legacy code.

Troubleshooting & edge cases

1. Missing values for placeholders

print("{} {} {}".format(1, 2))  # IndexError: Replacement index 2 out of range

Fix: Ensure you provide exactly as many values as placeholders, or use named placeholders.

2. KeyError in .format() with dict unpacking

data = {"name": "Alice"}
print("{name} is {age}".format(**data))  # KeyError: 'age'

Fix: Use .get() or default values: "{name} is {age}".format(**data, age="unknown")

3. Float precision surprises

print(f"{1/3:.2f}")   # 0.33 – correct
print(f"{1/3:.20f}")  # 0.33333333333333331483 – floating-point artifact

Fix: For financial calculations, use decimal.Decimal before formatting. For display, rounding to 2–4 places is usually fine.

4. Missing f prefix on f-strings

name = "Alice"
message = "{name}"  # prints the literal {name}
print(message)

Output: {name} (not Alice)

Fix: Add the f prefix: f"{name}"

What you learned & what's next

You now understand the core idea behind format strings with f-strings and format(). You can: - Insert variables and expressions into strings cleanly - Control alignment, padding, and numeric precision - Choose between f-strings (static) and .format() (dynamic) based on your needs - Troubleshoot common issues like missing values and float precision

With this skill, you can generate reports, format user-facing messages, and build data tables without string concatenation headaches. Up next, you’ll explore string methods — slicing, splitting, joining, and searching — so you can parse and manipulate text data efficiently.

Remember: format strings are the bridge between raw data and beautiful output. Master them, and your code reads like a story, not a puzzle.

Practice recap

Write a script that reads a list of product dictionaries (name, price, quantity) and prints a receipt. Use f-strings to format the price to two decimals, right-align totals in a column, and center the header. Try converting one row to use .format() with named placeholders to see the difference.

Common mistakes

  • Forgetting the f prefix on f-strings — without it, {variable} stays as literal text.
  • Mismatching placeholder count with .format() — Python raises an IndexError if you have more placeholders than arguments.
  • Assuming f-strings are safe when the template comes from user input — avoid eval()-like scenarios; use .format() with only safe keys.
  • Confusing : alignment specifiers: left <, right >, center ^ — easy to mix up and produce misaligned columns.

Variations

  1. Use formatted string literals (f-strings) for speed and readability in static templates.
  2. Use the % operator for legacy Python 2 codebases — but avoid in new Python 3 projects.
  3. Use string.Template for user-supplied templates where you want to restrict placeholder syntax to $var or ${var}.

Real-world use cases

  • Generate dynamic email templates that insert user name, order total, and date — f-strings make it readable and fast.
  • Format currency values in financial reports with two decimal places and dollar signs using :.2f specifier.
  • Build aligned columns for CLI tools (like ps tables) using width specifiers and alignment characters in .format().

Key takeaways

  • F-strings (prefix f) evaluate expressions inside {} at runtime — use them for static templates.
  • The .format() method works with dynamic templates and supports named placeholders.
  • Format specifiers after : control alignment (<, >, ^), width, and numeric types (d, f, %).
  • Float formatting with :.2f rounds numbers — for exact decimals, use decimal.Decimal first.
  • Always match the number of placeholders and values when using .format() — mismatch raises IndexError.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.