Python template strings, also called t-strings, let you inspect literal text and interpolated values before joining them. Introduced in Python 3.14, they use a t prefix and produce a string.templatelib.Template object instead of a finished string.
This separation supports safe HTML generation, structured logging, internationalization, command building, and other tasks that need to validate or transform inserted values.
Write Your First t-string
A t-string looks similar to an f-string, but its result keeps the template structure.
Example:
name = "Aarav"
template = t"Hello, {name}!"
# Display the type and stored values
print(type(template).__name__)
print(template.values)
Output:
Template
('Aarav',)
Version requirement: Template string literals require Python 3.14 or later. Earlier Python versions report a syntax error for the t prefix.
t-strings vs f-strings
| Feature | f-string | t-string |
|---|---|---|
| Prefix | f | t |
| Result type | str | Template |
| Values joined immediately | Yes | No |
| Processor can inspect expressions | No | Yes |
| Main purpose | Direct formatting | Custom and controlled processing |
Use an f-string when you only need a formatted string. Use a t-string when another function should decide how values are escaped, formatted, logged, translated, or validated.
Inspect a Template Object
A template stores literal sections in strings and inserted values in interpolations. The values property provides the evaluated values directly.
Example:
product = "Keyboard"
price = 2499.5
template = t"{product} costs Rs. {price:.2f}"
# Inspect the static text around the expressions
print(template.strings)
print(template.values)
# Inspect details preserved for the price expression
price_part = template.interpolations[1]
print(price_part.expression)
print(price_part.format_spec)
Output:
('', ' costs Rs. ', '')
('Keyboard', 2499.5)
price
.2f
Each interpolation can retain four useful details:
- value: the evaluated Python object.
- expression: the source text inside the braces.
- conversion: an optional conversion such as
r,s, ora. - format_spec: the text after the colon, such as
.2f.
The template does not automatically apply a format specification. Your processor decides whether and how to use it.
Process a Template
A Template is iterable. Iteration returns literal strings and Interpolation objects in their original order. You can use that sequence to build a result.
Example:
from string.templatelib import Interpolation
def render_text(template):
parts = []
for item in template:
if isinstance(item, Interpolation):
# Apply the stored format when one is present
value = (
format(item.value, item.format_spec)
if item.format_spec
else str(item.value)
)
parts.append(value)
else:
# Keep each literal section unchanged
parts.append(item)
return "".join(parts)
customer = "Olivia"
total = 1250.5
message = t"Customer: {customer}; Total: {total:.2f}"
print(render_text(message))
Output:
Customer: Olivia; Total: 1250.50
Escape Values for Safe HTML
Directly inserting untrusted text into HTML can create broken markup or a cross-site scripting risk. A t-string processor can escape every dynamic value while keeping trusted literal markup.
Example:
from html import escape
from string.templatelib import Interpolation
def render_html(template):
output = []
for item in template:
if isinstance(item, Interpolation):
# Escape dynamic data before adding it to HTML
output.append(escape(str(item.value)))
else:
# Literal HTML comes from the developer's template
output.append(item)
return "".join(output)
user_name = "<script>alert('x')</script>"
card = t"<p>Welcome, {user_name}</p>"
print(render_html(card))
Output:
<p>Welcome, <script>alert('x')</script></p>
Security note: A t-string does not sanitize data by itself. Safety comes from the processor you choose or write. Use a mature templating library for complex HTML applications.
Validate Interpolated Expressions
Because each interpolation preserves its expression text and value, a processor can reject unsupported data before creating output.
Example:
from string.templatelib import Interpolation
def render_log(template):
parts = []
for item in template:
if isinstance(item, Interpolation):
# Accept only simple values in this logging format
if not isinstance(item.value, (str, int, float, bool)):
raise TypeError(
f"Unsupported value in {item.expression}"
)
parts.append(str(item.value))
else:
parts.append(item)
return "".join(parts)
request_id = 8042
status = "completed"
entry = t"Request {request_id}: {status}"
print(render_log(entry))
Output:
Request 8042: completed
Use Conversions and Format Specifications
t-strings accept familiar interpolation syntax, including !r, !s, !a, debug expressions, and format specifications. They preserve this information rather than forcing one rendering policy.
Example:
temperature = 28.456
template = t"Reading: {temperature!r:.1f}"
# Show the metadata available to a processor
part = template.interpolations[0]
print(part.value)
print(part.conversion)
print(part.format_spec)
Output:
28.456
r
.1f
Raw and Multiline Template Strings
You can combine the raw and template prefixes as rt or tr. Raw t-strings keep backslashes in literal sections. Triple quotes support multiline templates.
Example:
folder = "reports"
# Keep the backslashes in the literal path
path_template = rt"C:\data\{folder}\latest.csv"
print(path_template.strings)
print(path_template.values)
Output:
('C:\\data\\', '\\latest.csv')
('reports',)
Best Practices
- Use t-strings only when a processor needs access to the template structure.
- Define one clear processing policy for each output type, such as HTML, SQL, logs, or terminal text.
- Treat dynamic values as untrusted until the processor validates or escapes them.
- Respect stored conversion and format information when users expect normal formatting behavior.
- Test empty strings, repeated expressions, nested templates, and invalid value types.
- Do not confuse t-strings with
string.Template, which uses dollar-sign placeholders and is a different API.
Conclusion
Python t-strings preserve literal text, values, expressions, conversions, and format specifications in a Template object. This gives your processor control over how output is built. Use them when validation, escaping, or structured processing matters more than immediate string formatting.