Python’s new t-strings

What t-strings are

  • t-strings (t"...") look like f-strings but compile to a Template object, not a str.
  • The Template contains:
    • the literal string chunks, and
    • Interpolation objects for each {expr} with the value, expression text, and format spec.
  • Interpolations are evaluated immediately (like f-strings), but concatenation is deferred to library code.

Difference from f-strings / .format

  • f-strings: f"...{x}..." -> str immediately; no trace of which parts were dynamic.
  • t-strings: t"...{x}..." -> Template; a library can inspect each placeholder and decide how to render or escape it, or even not produce a string at all (e.g. build a DOM or SQL AST).
  • Conceptually: f-strings = .format done at compile time; t-strings = “custom, pluggable .format” with full structure preserved.

Main use cases discussed

  • SQL: replace execute("... ? ...", (name,)) with execute(t"… WHERE name={name}"), letting the DB API build parameterized queries and prevent injection.
  • HTML: pass t"<p>{evil}</p>" to a function that escapes values and/or builds a DOM.
  • Shell / subprocess (PEP 787): safely interpolate arguments into commands without shell injection.
  • Logging: log.debug(t"...{counter}...") lets the logger skip string construction when the log level is disabled.

Safety, typing, and API design

  • Because Template is a different type from str and intentionally lacks __str__, APIs can:
    • accept only Templates (and reject raw strings),
    • separate “safe” (execute(template)) and “unsafe” (execute_unsafe(str)) paths.
  • Debate on backwards compatibility: existing DB APIs all take strings; options include adding new template-only methods, overloading with deprecation, or introducing “safe” variants.
  • Some worry the tiny f vs t visual difference is a footgun; others counter that type checkers and runtime type errors will catch misuse.

Syntax, tooling, and JS comparisons

  • Some wanted JS-style tagged literals (sql"SELECT…" / html"<p>…"), which would help syntax highlighting and type distinctions per language.
  • PEP explicitly rejected arbitrary user-defined prefixes; tooling is expected to infer context via types, annotations, or common call patterns (e.g. html(t"...")).
  • Concerns about “yet another string prefix” and readability vs. arguments that prefixes enable richer editor support (embedded SQL/HTML linting).

Language complexity and philosophy

  • Supporters see t-strings as a small, orthogonal feature solving real, long-standing security and ergonomics issues.
  • Critics see them as more “syntax bloat” alongside many existing formatting mechanisms, moving Python further from “one obvious way” and toward feature creep.