Formatter.parse
The parser behind str.format, exposed. Each tuple is "some literal text, then maybe one field"; {{ and }} come out as literal braces, and a malformed string raises ValueError when the iterator reaches the bad spot.
Demo
import string list(string.Formatter().parse('Hi {name!r:>10}, you owe {0:.2f}'))
A field with no spec gives '' for format_spec, while a piece with no field gives None — that is how you tell them apart. '{{' is returned as literal text ending in '{' (the parser splits there). parse() does not look inside a format spec: in '{x:{w}}' it reports one field x with the spec '{w}', so a fields-in-spec name like w only shows up if you parse the spec again. Empty {} fields come back with field_name '' — the numbering happens later, in vformat.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| format_string | str | yes | A format string in str.format syntax. Anything else raises TypeError. |
Return value
iterator of tuple[str, str | None, str | None, str | None] — One tuple per piece: the literal text before a field, then the field (or None, None, None when there is no field).
Common patterns
import string, re keys = {re.split(r"[.\[]", name, 1)[0] for _, name, _, _ in string.Formatter().parse(fmt) if name}
import string try: parts = list(string.Formatter().parse(fmt)) except ValueError as e: print(f"bad format string: {e}")
import string out = [] for lit, name, spec, conv in string.Formatter().parse(fmt): out.append(lit.replace("{", "{{").replace("}", "}}")) if name is not None: out.append("{" + name + ("!" + conv if conv else "") + (":" + spec if spec else "") + "}") "".join(out)
Examples
Pitfalls
import string [name for _, name, _, _ in string.Formatter().parse('{}-{x}') if name]
import string [name for _, name, _, _ in string.Formatter().parse('{}-{x}') if name is not None]
import re re.findall(r'{(\w+)}', 'use {{name}} for {name}')
import string [n for _, n, _, _ in string.Formatter().parse('use {{name}} for {name}') if n is not None]
When to use
- Listing the placeholders of a format string (mail merge, i18n checks)
- Validating or rewriting format strings before using them
- Overriding it in a subclass to support a different field syntax
- Formatting → just call format()/vformat()
- $-templates → Template.get_identifiers()
Notes
FAQ
[name for _, name, _, _ in string.Formatter().parse(s) if name is not None]. It handles {{ }}, conversions and specs correctly. Automatic fields {} appear as '' because they are numbered later.