๐Ÿ Python 3.14: t-Strings Look Like f-Strings, But They Aren’t Strings

An f-string takes your variables and glues them into a string immediately. That’s lovely for greetings and terrible for SQL, HTML and shell commands, where “just glue it” is how injection bugs are born.

Python 3.14, released on 7 October 2025, adds a sibling: the template string.

The discovery: Same syntax, different result

A t-string uses a t prefix instead of f. Unlike an f-string, it doesn’t return a str. It returns an object that keeps the static and interpolated parts separate:

>>> variety = 'Stilton'
>>> template = t'Try some {variety} cheese!'
>>> type(template)
<class 'string.templatelib.Template'>
>>> list(template)
['Try some ', Interpolation('Stilton', 'variety', None, ''), ' cheese!']

Iterating over a Template gives you plain strings for the static text and Interpolation objects for the {...} parts. That output comes straight from the “What’s new in Python 3.14” page, which describes the feature in PEP 750.

A concrete example

Because the code that renders the result can tell trusted text from interpolated values, it can treat them differently. Here’s a small HTML renderer that escapes only the interpolated parts:

from html import escape
from string.templatelib import Interpolation

def safe_html(template):
    parts = []
    for part in template:
        if isinstance(part, Interpolation):
            parts.append(escape(str(part.value)))
        else:
            parts.append(part)
    return "".join(parts)

name = '<script>alert("hi")</script>'
print(safe_html(t"<p>Hello, {name}</p>"))
# <p>Hello, &lt;script&gt;alert(&quot;hi&quot;)&lt;/script&gt;</p>

The Python documentation suggests the same idea for sanitising user input, and mentions SQL, shell operations, logging and HTML as candidates.

The important nuance: The template does nothing by itself

A t-string is not a safer f-string. It’s the raw material. All the safety comes from the function you pass it to:

  • A Template is not a str, so existing APIs that expect strings won’t understand it. Libraries have to add explicit support for Template.
  • My example ignores the interpolation’s conversion and format spec for brevity. A real renderer should decide what to do with them.
  • Escaping depends on context. Text that’s safe inside an HTML element isn’t automatically safe inside an attribute or a script block.

This feature requires Python 3.14 or later.

The takeaway โ˜•

Use f-strings for text you’re about to display. Reach for t-strings when a library or your own function needs to treat interpolated values differently from the surrounding text.

Same curly braces, very different responsibilities.

References

Related articles