T-strings and templatelib: Structured Interpolation

Published on: October 22, 2026
Reading time: 5 minutes
Python programming code displayed on a screen

T-strings are a Python 3.14 feature designed to represent interpolated text as structured data. Their syntax resembles f-strings, but they do not immediately produce a final string. Instead, they return a template object that keeps literal text, interpolated values, conversions, and format specifications separate. This distinction lets an application validate, escape, transform, audit, or route each value before producing output.

The feature is provided by string.templatelib. It is useful whenever direct string construction would discard information that a library needs. Common examples include safe HTML rendering, structured logging, internationalization, query builders, command generators, and domain-specific languages.

How t-strings differ from f-strings

An f-string evaluates expressions and returns a regular str. That is convenient for simple messages, but the original structure is lost. Once the string is assembled, a consumer cannot reliably tell which characters were written by the developer and which came from variables. A t-string preserves those boundaries.

name = "Ana"
age = 28
template = t"User: {name}, age: {age}"

print(type(template))
print(template.strings)
print(template.interpolations)

The strings attribute contains literal segments. The interpolations attribute contains the inserted values and their metadata. A renderer can process these components according to its own rules rather than receiving one opaque string.

Template and Interpolation objects

The module primarily exposes Template and Interpolation. A Template represents the complete ordered sequence. Each Interpolation stores the evaluated value, the source expression text, an optional conversion, and a format specification.

For example, an interpolation such as {price:.2f} retains both the value and .2f. A renderer may honor that specification, reject it, replace it, or apply a domain-specific formatting policy. The same applies to conversions such as !r.

Iterating over a template

A template can be iterated in source order. The iteration yields literal strings and interpolation objects, which makes custom rendering straightforward.

from string.templatelib import Interpolation

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

user = "Carlos"
print(render(t"Hello, {user}!"))

This renderer is intentionally minimal. A production renderer could escape HTML, redact secrets, preserve numeric types for telemetry, generate tokens, or return a data structure instead of a string.

Safer HTML rendering

One compelling use case is context-aware escaping. Inserting external data directly into HTML can create vulnerabilities when values are not escaped correctly. A t-string allows a renderer to escape only interpolated values while leaving trusted literal markup intact.

from html import escape
from string.templatelib import Interpolation

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

comment = "<script>alert('x')</script>"
page = safe_html(t"<p>{comment}</p>")

T-strings do not automatically make output safe. They expose the structure needed to implement a safety policy. The renderer remains responsible for selecting the correct escaping strategy for the destination context.

Structured logging

A logging system can store expression names and values separately instead of flattening everything into text. This improves filtering, aggregation, alerting, and search.

def log_template(template):
    fields = {}
    for interpolation in template.interpolations:
        fields[interpolation.expression] = interpolation.value
    print({"message": template.strings, "fields": fields})

order_id = 845
status = "paid"
log_template(t"Order {order_id} became {status}")

The values remain typed, so an observability backend can treat an integer as an integer rather than parsing it from a formatted sentence. Sensitive fields can also be redacted based on expression names or value types.

Queries and commands

T-strings can serve as input to libraries that build queries or commands. A processor can convert interpolated values into placeholders, keep parameters separate, allow only approved types, and reject unsafe expressions. This is more reliable than manual concatenation.

However, a t-string alone does not prevent SQL injection or command injection. The consuming library must implement actual parameterization and context-specific validation. The benefit is that values and literal syntax are available separately, making a secure implementation possible.

Conversions and format specifications

T-strings preserve conversion and format_spec, but a renderer chooses whether and when to apply them. The module’s convert() helper can process supported conversions, while Python’s format() can apply a format specification.

from string.templatelib import Interpolation, convert

def formatted_render(template):
    result = []
    for item in template:
        if not isinstance(item, Interpolation):
            result.append(item)
            continue
        value = convert(item.value, item.conversion)
        result.append(format(value, item.format_spec))
    return "".join(result)

A robust renderer should handle empty specifications, missing conversions, invalid formats, and custom objects carefully. It may also restrict formatting features when templates come from less trusted sources.

Internationalization

Preserving interpolation boundaries can help translation systems. Instead of translating a fully assembled sentence, a tool can retain placeholders and provide translators with a stable message structure. The final renderer can then apply locale-specific number, date, and currency formatting.

This does not replace a complete internationalization framework. Plural rules, grammatical gender, locale selection, and message catalogs still require specialized handling. T-strings provide a useful structured input format for such tools.

When to use t-strings

Use t-strings when the interpolation structure matters after the expression is evaluated. They fit template engines, logging systems, safe markup generation, DSLs, localization pipelines, and libraries that inspect or validate values. For a simple message printed directly to a terminal, an f-string remains clearer and shorter.

Compatibility also matters. T-strings require Python 3.14 or later. A library supporting older versions must provide a fallback or raise its minimum supported version. For related topics, read the Academify guides to Python type hints, object introspection with inspect, debugging with f-strings, and the Advanced Python category.

Designing a good renderer

Keep each renderer narrow and context-specific. HTML, SQL, shell commands, URLs, and log records require different rules. Validate allowed value types, define how missing or invalid formats are handled, and avoid executing additional code during rendering. Tests should cover empty values, Unicode, markup characters, custom objects, secrets, malformed format specifications, and nested data.

Do not assume that every expression should become text. A structured logger may preserve the original object. A database adapter may turn it into a bound parameter. An HTML renderer may accept explicitly trusted markup through a dedicated wrapper type while escaping ordinary strings.

Performance considerations

T-strings introduce structured processing, so they are not automatically faster than f-strings. Their value is control, not raw speed. Avoid repeatedly inspecting the same template when a reusable compiled representation is possible. Measure performance in the real application and keep renderers simple.

For authoritative details, consult the official string.templatelib documentation and PEP 750, which explains the motivation and design of template strings.

Conclusion

T-strings are not a universal replacement for f-strings. They solve a different problem: preserving an interpolated expression as structured data so another component can make informed decisions. By separating literals, values, conversions, and formats, string.templatelib enables safer renderers, richer logs, better tooling, and domain-specific processing. Use f-strings when you simply need text; choose t-strings when you need control over how that text is produced.

Share:

Facebook
WhatsApp
Twitter
LinkedIn

Article content

    Related articles

    SQLite database and Python code for selective iterdump export
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    SQLite iterdump: Create Selective Dumps in Python

    Learn sqlite3.Connection.iterdump filters for selective SQLite dumps, dependency checks, validation, and safer restoration.

    Ler mais

    Tempo de leitura: 4 minutos
    21/10/2026
    Code and files representing Python data compression
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    compression.zstd: Fast Zstandard in Python

    Learn Python compression.zstd for fast file and data compression, streaming, integrity checks, and safe decompression.

    Ler mais

    Tempo de leitura: 7 minutos
    21/10/2026
    Configuration file and code structure for Python ConfigParser
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    ConfigParser: Read INI Files Without Sections

    Learn Python ConfigParser unnamed sections with validation, typed values, compatibility, layered settings, and safe INI writing.

    Ler mais

    Tempo de leitura: 5 minutos
    20/10/2026
    Binary data and computer memory representing Python memoryview
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    memoryview count and index: Search Without Copies

    Learn Python memoryview count and index to search values in zero-copy buffers and validate binary data efficiently.

    Ler mais

    Tempo de leitura: 5 minutos
    20/10/2026
    Developer working with Python code and data validation
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    map strict: Detect Misaligned Iterables

    Learn Python map strict to validate iterables, prevent silent truncation, and detect misaligned data early.

    Ler mais

    Tempo de leitura: 4 minutos
    19/10/2026
    Organized folders representing Python files and directories
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    pathlib.Path.info: Speed Up Directory Scans

    Learn pathlib.Path.info in Python to reuse file metadata, speed up directory scans, and avoid stale cache assumptions.

    Ler mais

    Tempo de leitura: 6 minutos
    19/10/2026