AI Skill Report Card
Formatting Strings with Python
---
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
Quick Start14 / 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
Workflow14 / 15
Progress:
- Step 1: Decide the right tool — f-string (static, dev-controlled),
str.format()(reusable template, dev-controlled), orstring.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.Formatterand overrideformat_field/get_value - Step 4: For generating random strings/tokens, combine
string.ascii_letters,digits,punctuationwithrandom/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:
Pythonf"{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)
Examples18 / 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:
Pythonfrom 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:
Pythonfrom 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:
Pythonimport 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
Best Practices
- 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.samplewithstringconstants only for non-security purposes (test data, IDs); usesecretsmodule for tokens, passwords, or anything security-sensitive. - Reuse
Formattersubclassing 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
localemodule orBabellibrary rather than hardcoding,.
Common Pitfalls
- 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. Usestring.Templateinstead. - Forgetting
safe_substitutevssubstitute—substituteraisesKeyErroron missing placeholders;safe_substitutesilently leaves them unresolved (choose deliberately, don't default blindly). - Confusing
string.punctuation/whitespaceplatform 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.