string.Template

Three rules: $identifier and ${identifier} are placeholders, $$ is a $, and any other $ is an error. That small surface is the point — a template written by a user or translator can only fill in names you provide.

string classPython 2.4+Live demo
Common call
Template('$who likes $what').substitute(who='Ada', what='tea')
Returns
'Ada likes tea'
Replaces
str.format / f-strings for templates that come from config files or users
Watch out
identifiers are ASCII only: $naïve is the placeholder $na followed by ïve
string.Template(templatetemplate — The template text. Stored unchanged as the instance attribute .template.type: str · required)
→ Template

Demo

Live evaluation
Fill $name and $item. Try ${...} to glue a placeholder to letters, and $$ for a literal dollar.
Try:
Inputs
textstrtemplate using $name and $item
namestrvalue for name
itemstrvalue for item
Code
from string import Template
Template('Dear $name, your $item has shipped.').substitute(name='Ada', item='book')
Result
'Dear Ada, your book has shipped.'

A placeholder name is the longest run of ASCII letters, digits and underscores after the $, so '$items' asks for items, which is missing (KeyError) — '${item}s' is the fix. A $ followed by a space raises "Invalid placeholder in string: line 1, col 10" in the bare-$ case: the line and column (counted from 1) of that $. In '$naïve' the name stops before ï, so only na is looked up.

Parameters

NameTypeRequiredDescription
templatestryesThe template text. Stored unchanged as the instance attribute .template.

Return value

Template — A template object. The text is kept in its .template attribute; nothing is parsed until you substitute.

Common patterns

Templates from a config file
Load the text, substitute known names, keep anything unknown visible.
from string import Template
with open('welcome.txt', encoding='utf-8') as f:
    tpl = Template(f.read())
message = tpl.safe_substitute(name=user.name, plan=user.plan)
Values from a dict
Pass a mapping positionally; keyword arguments override it.
from string import Template
Template('$host:$port').substitute(config, port=8080)
Check a template before saving it
is_valid and get_identifiers (3.11+) let an editor reject bad templates.
from string import Template
tpl = Template(user_text)
if not tpl.is_valid():
    raise ValueError('stray $ in template')
unknown = set(tpl.get_identifiers()) - {'name', 'plan'}

Examples

1. Keywords
from string import Template Template('$who likes $what').substitute(who='tim', what='kung pao')
Returns
'tim likes kung pao'
2. A dict, overridden by a keyword
from string import Template Template('$a $b').substitute({'a': 1, 'b': 2}, b=3)
Returns
'1 3'
3. Braces separate the name
from string import Template Template('${noun}ification').substitute(noun='simpl')
Returns
'simplification'
4. $$ is a dollar sign
from string import Template Template('Give $$5').substitute()
Returns
'Give $5'
5. Values go through str()
from string import Template Template('$n items').substitute(n=3)
Returns
'3 items'
6. Missing name
from string import Template Template('$who likes $what').substitute(who='tim')
Returns
KeyError: 'what'
7. The text is kept as .template
from string import Template Template('$a').template
Returns
'$a'

Pitfalls

1. Gluing a placeholder to letters
The name runs as far as identifier characters go, so text right after a placeholder becomes part of its name.
$noun + text
from string import Template
Template('$nounification').substitute(noun='simpl')
KeyError: 'nounification'
${noun}
from string import Template
Template('${noun}ification').substitute(noun='simpl')
'simplification'
2. Prices and other literal dollars
A $ that does not start a valid placeholder is an error in substitute. Double it.
$5
from string import Template
Template('Cost: $5').substitute()
ValueError: Invalid placeholder in string: line 1, col 7
$$5
from string import Template
Template('Cost: $$5').substitute()
'Cost: $5'
3. Expecting attribute or index access
$user.name is the placeholder $user followed by the text ".name". Flatten the values first.
$user.name
from string import Template
Template('$user.name').substitute(user='ada')
'ada.name'
flat names
from string import Template
user = {'name': 'Ada'}
Template('$user_name').substitute(user_name=user['name'])
'Ada'

When to use

Use it
  • Message templates edited by users, admins or translators
  • Config files with ${VAR}-style placeholders
  • Any template whose author you do not fully trust
Reach for something else
  • Formatting numbers, dates, alignment → f-strings / str.format (Template has no format specs)
  • Loops, conditionals, HTML → a template engine (Jinja2)

Notes

CPython impl
Lib/string.py — one regular expression (Template.pattern) with the groups escaped, named, braced and invalid, applied with pattern.sub()
Identifiers
Default idpattern (?a:[_a-z][_a-z0-9]*) with re.IGNORECASE: ASCII letters of either case, digits, underscore, not starting with a digit
Subclassing
delimiter, idpattern, braceidpattern, flags or the whole pattern can be overridden in a subclass — see Template class attributes
Safety
Substitution only calls str() on the values you pass; the template cannot reach attributes, items or code

FAQ

f-strings are for code you write: they are evaluated where they appear. Template is for text that arrives at runtime — config, translations, user settings. It only replaces $names with the values you pass, so it cannot run code or read attributes.