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 or tr—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

  1. Use Python 3.14 (final version or pre-release).
  2. Prefix strings with t (e.g., t”Hello {x}”).
  3. 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 🙂