033. .Format() Method
Template strings with placeholder substitution
033. .Format() Method
RAM Manager: Reading Legacy Code
Aryan is adding features to his company’s existing monitoring tool. The codebase is Python 3.4-era — everything uses .format() because f-strings didn’t exist yet. He needs to understand and fix it.
# Common .format() patterns he finds in the codebase
"{name} [{pid}]: {mem}MB".format(name="chrome", pid=812, mem=544)
"PID {0:>6} | {1:<20} | {2:>6}MB".format(812, "chrome", 544)The broken templates have two bugs: a wrong index ({3} when only 3 args are passed, so index 2 is the last) and a mismatched keyword name ({message} when the kwarg is msg=). Both cause exceptions at runtime — the kind of bug that only surfaces when you actually run the formatter.
💡 Fun fact: .format() was introduced in Python 2.6 (2008) as a replacement for the % operator. F-strings didn’t arrive until Python 3.6 (2016) — so .format() ruled Python string formatting for nearly a decade and is still widely used in legacy codebases.
⚠️ Watch out: A KeyError or IndexError from .format() only fires at runtime, not at import time. A template like "Hello {nmae}" with a typo will sit silently in your code until that line actually executes — unit tests are the only reliable way to catch this early.
🤔 Think about it: If .format() raises a KeyError when a named placeholder has no matching keyword, why does "{} {}".format("a") raise an IndexError instead? What does that tell you about how Python handles positional vs. named placeholders internally?
Learning objectives
- Use positional placeholders {0}, {1} with .format()
- Use named placeholders {name} with .format(name=value)
- Apply format specifiers for alignment and precision
Key concepts
- format()
- string templates
- placeholders
Try it
Concept detail
str.format() replaces {} placeholders with arguments.
Positional: “Hello {0} and {1}”.format(“Alice”, “Bob”) → “Hello Alice and Bob” Auto-numbered: “Hello {} and {}”.format(“Alice”, “Bob”) → same (Python counts for you) Named: “Hello {name}”.format(name=“Alice”) → “Hello Alice” Mixed: “{0} is {age}”.format(“Alice”, age=30) → “Alice is 30”
Format specs: same mini-language as f-strings “{:.2f}”.format(3.14159) → “3.14” “{:>10}”.format(“hi”) → “ hi“ “{:<10}”.format(“hi”) → “hi “
Runtime errors .format() raises: IndexError if a positional index is out of range KeyError if a named placeholder has no matching keyword argument
.format() is pre-3.6 but still used for: reusable template strings stored in config files or databases, and code that needs to run on Python < 3.6.
Solution
def make_invite(name, event, date):
return "Dear {0}, you're invited to {1} on {2}.".format(name, event, date)
def make_error(code, msg):
return "Error {code}: {msg}".format(code=code, msg=msg)
def make_table_row(rank, name, score):
return "{:3}. {:<10} {}".format(rank, name, score)Tests
def test_invite():
result = make_invite("Alice", "PyCon", "2024-05-10")
assert result == "Dear Alice, you're invited to PyCon on 2024-05-10."
def test_invite_no_index_error():
# {3} raises IndexError — make sure it runs without error
try:
result = make_invite("Bob", "DjangoCon", "2024-09-22")
assert "Bob" in result
except IndexError:
assert False, "IndexError raised — wrong index in template"
def test_error():
result = make_error(404, "Page not found")
assert result == "Error 404: Page not found"
def test_error_no_key_error():
try:
result = make_error(500, "Internal error")
assert "500" in result
except KeyError:
assert False, "KeyError raised — mismatched keyword name"
def test_table_row():
result = make_table_row(1, "Alice", 100)
assert result.startswith(" 1.")
assert "Alice" in result
assert "100" in result