Python 3.14 introduces template strings, also known as t‑strings, through PEP 750. These represent a powerful generalization of f‑strings—rather than evaluating directly to strings, t‑strings produce a Template
object that preserves the syntax structure and interpolations. This opens up richer possibilities for safe and flexible string handling
While f‑strings
are convenient and powerful, they lack a mechanism to intercept and transform interpolated values. This limitation can lead to risks such as SQL injection or unintended XSS when embedding untrusted input into strings. T‑strings address these issues by giving you access to the pieces of the string before they’re turned into a single literal
For example:
from string.templatelib import Template
evil = "<script>alert('evil')</script>"
template = t"<p>{evil}</p>"
# The html() processor can safely escape interpolations before rendering.
This makes template strings ideal for building safer SQL queries, HTML generation, logging, and domain-specific processing.
2. Syntax & Basic Behavior
A t‑string
uses the t
(or T) prefix, just like f‑strings
use f
:
template = t"Hello, {name}!"
But instead of returning a str, this evaluates to a Template object defined in the string.templatelib module.
The Template exposes:
- .strings: tuple of literal text segments
- .interpolations: tuple of Interpolation objects (one per {…} placeholder)
- .values: tuple of actual evaluated values across interpolations
Example:
>>> name = "Alice"
>>> templ = t"Hi {name}!"
>>> templ.strings
('Hi ', '!')
>>> templ.interpolations[0].value
'Alice'
3. The Interpolation Object
Each placeholder produces an Interpolation instance with attributes:
- value: the evaluated result
- expression: the literal expression text, e.g., “name”
- conversion: conversion verb like r, s, or a (or None)
- format_spec: any format specifier, e.g., .2f
Example:
>>> value = 42
>>> templ = t"Value: {value:.2f}"
>>> interp = templ.interpolations[0]
>>> interp.value
42
>>> interp.expression
'value'
>>> interp.format_spec
'.2f'
4. Iterating the Contents
You can loop through a Template to retrieve its parts in sequence. The interleaved iteration skips empty strings:
>>> templ = t"Hello {name}!"
>>> list(templ)
['Hello ', Interpolation(...), '!']
This pattern allows detailed control during processing.
5. Concatenation & Raw Strings
- Explicit concatenation: you can + two Template objects:
templ = t"Hello " + t"{name}"
- Implicit concatenation of literal
t‑strings
also works. - Raw template strings: prefix with
rt
ortr
—interpolations still work, but backslashes are preserved literally:
templ = rt"Line:\n{name}"
# "\n" remains two characters, not a newline
6. Custom Processing Examples
HTML Templating
Build safe HTML with auto-escaping and attribute handling:
from string.templatelib import Template
def html(template: Template) -> Element:
...
text = "<script>alert('XSS')</script>"
templ = t"<p>{text}</p>"
escaped = html(templ) # Interpolation is automatically HTML-escaped.
This approach also supports maps for attribute interpolation, boolean attributes, nested elements, and even interpolating tag names dynamically.
Structured Logging
T‑strings can embed both formatted messages and structured data:
logger.info(t"User {action}: {amount:.2f} {item}")
This can produce a message and also log the dictionary of values separately, supporting structured logs.
SQL Queries—With Psycopg
Psycopg (3.3+) supports using t‑strings directly in cursor.execute to isolate parameters safely:
cursor.execute(
t"SELECT * FROM table WHERE id = {id}"
)
Internally, it separates the query structure from the values, avoiding manual sanitization.
Comparison: F-Strings vs T-Strings
Feature | F-Strings | T-Strings (Template) |
Prefix | f, F | t, T |
Evaluate to | str | Template object |
Access to values | No | Yes (via .interpolations) |
Safe sanitizing | No (prone to injection) | Yes (with processing functions) |
Use cases | Simple formatting | DSLs, templating, logging, SQL |
Practical Benefits & Developer Insights
- Security: Offers safer patterns against injection vulnerabilities by separating structure and data.
- Flexibility: Developers can build domain-specific logic—HTML escaping, query parameter binding, logging metadata capture—on top of T‑strings.
- Tooling support: Since the syntax mirrors f‑strings, popular editors and formatters are expected to support t‑strings easily.
From community discussion:
“It’s a way of writing string literals … that if anything makes injection less likely.”
“
f‑strings
are great, but they can be a trap if you accidentally pass them to your database without sanitizing.”
Getting Started with T-Strings
- Use Python 3.14 (final version or pre-release).
- Prefix strings with t (e.g., t”Hello {x}”).
- Import and inspect the Template object:
from string.templatelib import Template
4. Write a custom processor:
def render(tmpl: Template) -> str:
parts = []
for part in tmpl:
if isinstance(part, Interpolation):
parts.append(str(part.value)) # Or safely process
else:
parts.append(part)
return "".join(parts)
5. Build on examples—templating, SQL, logging—to leverage the power of T-strings.
Conclusion
PEP 750 introduces T-strings (template strings) — a powerful evolution of Python string interpolation. With t-strings, developers gain structured access to interpolation data, enabling safer and more powerful string processing. From sanitizing user input to building domain-specific languages, the possibilities are vast. As Python 3.14 adoption grows, expect T-strings to become a foundation for safer, cleaner, and more expressive code.
Happy Learning 🙂