AI Skill Report Card

Formatting Strings with Python

A86·Aug 14, 2026·Source: Web
---
name: formatting-strings-with-python
description: Applies Python's string module and format-string mini-language to build templates, custom formatters, and safe string substitution. Use when working with str.format(), f-strings, string.Template, Formatter subclasses, or string constants like ascii_letters/digits/punctuation.
---

# Formatting Strings with Python
14 / 15
Python
# Format spec mini-language f"{value:>10.2f}" # right-align, 2 decimals f"{value:,}" # thousands separator f"{value:.1%}" # percentage # string.Template for user-facing substitution (safer than % or .format for untrusted input) from string import Template t = Template("Hello, $name! You have $count new messages.") t.substitute(name="Ana", count=3) t.safe_substitute(name="Ana") # missing keys left as-is instead of raising # Useful constants import string string.ascii_letters # 'abcdefghij...XYZ' string.digits # '0123456789' string.punctuation # '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
Recommendation
Add an example showing a bad/insecure outcome (e.g., f-string injection) alongside the fix to strengthen the security warning
14 / 15

Progress:

  • Step 1: Decide the right tool — f-string (static, dev-controlled), str.format() (reusable template, dev-controlled), or string.Template (untrusted/user-supplied templates)
  • Step 2: Choose format spec ({:spec}) for numeric/alignment/width needs
  • Step 3: For repeated custom formatting logic, subclass string.Formatter and override format_field/get_value
  • Step 4: For generating random strings/tokens, combine string.ascii_letters, digits, punctuation with random/secrets
  • Step 5: Test edge cases — missing keys, special characters, locale-sensitive numbers

Format Spec Mini-Language Reference

[[fill]align][sign][#][0][width][,|_][.precision][type]

align: < > ^ =        (left, right, center, pad-after-sign)
sign:  + - ' '         (always show, only negative, space for positive)
type:  d f e g % x o b n s

Common patterns:

Python
f"{n:04d}" # zero-padded int, width 4 -> "0007" f"{n:+d}" # force sign -> "+7" f"{pi:.3f}" # 3 decimal places -> "3.142" f"{big:,}" # comma thousands separator -> "1,234,567" f"{ratio:.2%}" # percentage with 2 decimals -> "45.67%" f"{text:^20}" # center in width 20 f"{n:#x}" # hex with 0x prefix
Recommendation
Include a brief note on when str.format() is still preferable over f-strings (e.g., templates defined separately from data)
18 / 20

Example 1: Safe template for user-editable messages Input: App lets users customize a notification template like "Hi $user, your order $order_id shipped." Output:

Python
from string import Template template = Template(user_supplied_template) message = template.safe_substitute(user="Ana", order_id="A1023") # safe_substitute avoids KeyError crashes if a $variable is missing/mistyped

Example 2: Custom Formatter for domain objects Input: Need {obj:currency} to format a Decimal as $1,234.50. Output:

Python
from string import Formatter from decimal import Decimal class MyFormatter(Formatter): def format_field(self, value, spec): if spec == "currency": return f"${value:,.2f}" return super().format_field(value, spec) fmt = MyFormatter() fmt.format("Total: {0:currency}", Decimal("1234.5")) # -> "Total: $1,234.50"

Example 3: Generating a random alphanumeric token Input: Need an 8-char token from letters+digits. Output:

Python
import secrets, string alphabet = string.ascii_letters + string.digits token = "".join(secrets.choice(alphabet) for _ in range(8))
Recommendation
Consider trimming the Best Practices/Pitfalls overlap since some points repeat information already in Workflow
  • Prefer f-strings for internal/static formatting — fastest, clearest, evaluated at write time.
  • Use string.Template (not .format() or f-strings) when the template string comes from users, config files, or translators — it only substitutes $identifier/${identifier}, avoiding arbitrary attribute/method access.
  • Use random.choice/random.sample with string constants only for non-security purposes (test data, IDs); use secrets module for tokens, passwords, or anything security-sensitive.
  • Reuse Formatter subclassing when the same custom format types (currency, duration, etc.) are needed across many call sites — beats scattering manual string logic.
  • For number formatting with locale (comma vs. period), consider locale module or Babel library rather than hardcoding ,.
  • Using str.format() or f-strings on untrusted/user-provided template strings — allows access to object internals (e.g. "{0.__class__.__init__.__globals__}".format(x)), a real security risk. Use string.Template instead.
  • Forgetting safe_substitute vs substitutesubstitute raises KeyError on missing placeholders; safe_substitute silently leaves them unresolved (choose deliberately, don't default blindly).
  • Confusing string.punctuation/whitespace platform assumptions — these are ASCII-only, not full Unicode punctuation sets.
  • Misusing % old-style formatting mixed with new-style specs — stick to one style per codebase.
  • Forgetting {{ and }} to escape literal braces in .format()/f-strings.
0
Grade AAI Skill Framework
Scorecard
Criteria Breakdown
Quick Start
14/15
Workflow
14/15
Examples
18/20
Completeness
18/20
Format
14/15
Conciseness
14/15