Template.substitute / safe_substitute
Same substitution, two error policies. substitute is strict: every placeholder needs a value and every $ must be valid. safe_substitute never raises for those — it returns the unknown placeholders and stray $ unchanged.
Demo
from string import Template t = Template('Hello $name!') values = {'name': 'Ada'} try: strict = t.substitute(values) except (KeyError, ValueError) as e: strict = f'{type(e).__name__}: {e}' (t.safe_substitute(values), strict)
The ValueError message gives the line and the column, both counted from 1, of the $ that does not start a placeholder — in the stray-$ case that is line 2, col 9. '${ name }' is not a placeholder (no spaces allowed inside the braces), so it is invalid too. $$ always becomes a single $ and is never read as the start of a name. Values that are not used are simply ignored by both methods.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| mapping | mapping | no ({}) | Values by placeholder name (any object with __getitem__ that raises KeyError). Positional-only. |
| **kwds | any | no | Values as keyword arguments. They take precedence over mapping when both have the same name. |
Return value
str — The template text with every placeholder replaced by str(value) and every $$ by $.
Common patterns
from string import Template body = Template(EMAIL_BODY).substitute(name=user.name, link=reset_url)
from string import Template stage1 = Template(text).safe_substitute(site='example.org') final = Template(stage1).substitute(user='ada')
from string import Template t = Template(text) missing = [n for n in t.get_identifiers() if n not in values] if missing: raise KeyError(f'missing values: {missing}') t.substitute(values)
Examples
Pitfalls
from string import Template Template('Dear $nmae').safe_substitute(name='Ada')
from string import Template Template('Dear $nmae').substitute(name='Ada')
from string import Template try: out = Template('100$').substitute() except KeyError: out = 'missing value' out
from string import Template try: out = Template('100$').substitute() except (KeyError, ValueError) as e: out = f'bad template: {e}' out
When to use
- substitute — templates you control, where a missing value is a bug
- safe_substitute — user-edited templates, partial filling, previews
- Production output from user templates with safe_substitute alone → validate with is_valid()/get_identifiers() first
Notes
FAQ
substitute raises KeyError when a placeholder has no value and ValueError when a $ is not followed by a valid name; safe_substitute does neither and leaves those parts of the text unchanged. Both replace $$ with $.