CINXE.COM
PEP 750 – Template Strings | peps.python.org
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="color-scheme" content="light dark"> <title>PEP 750 – Template Strings | peps.python.org</title> <link rel="shortcut icon" href="../_static/py.png"> <link rel="canonical" href="https://peps.python.org/pep-0750/"> <link rel="stylesheet" href="../_static/style.css" type="text/css"> <link rel="stylesheet" href="../_static/mq.css" type="text/css"> <link rel="stylesheet" href="../_static/pygments.css" type="text/css" media="(prefers-color-scheme: light)" id="pyg-light"> <link rel="stylesheet" href="../_static/pygments_dark.css" type="text/css" media="(prefers-color-scheme: dark)" id="pyg-dark"> <link rel="alternate" type="application/rss+xml" title="Latest PEPs" href="https://peps.python.org/peps.rss"> <meta property="og:title" content='PEP 750 – Template Strings | peps.python.org'> <meta property="og:description" content="This PEP introduces template strings for custom string processing."> <meta property="og:type" content="website"> <meta property="og:url" content="https://peps.python.org/pep-0750/"> <meta property="og:site_name" content="Python Enhancement Proposals (PEPs)"> <meta property="og:image" content="https://peps.python.org/_static/og-image.png"> <meta property="og:image:alt" content="Python PEPs"> <meta property="og:image:width" content="200"> <meta property="og:image:height" content="200"> <meta name="description" content="This PEP introduces template strings for custom string processing."> <meta name="theme-color" content="#3776ab"> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all"> <title>Following system colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="9"></circle> <path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path> </svg> </symbol> <symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all"> <title>Selected dark colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path stroke="none" d="M0 0h24v24H0z" fill="none"></path> <path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path> </svg> </symbol> <symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all"> <title>Selected light colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="5"></circle> <line x1="12" y1="1" x2="12" y2="3"></line> <line x1="12" y1="21" x2="12" y2="23"></line> <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line> <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line> <line x1="1" y1="12" x2="3" y2="12"></line> <line x1="21" y1="12" x2="23" y2="12"></line> <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line> <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line> </svg> </symbol> </svg> <script> document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto" </script> <section id="pep-page-section"> <header> <h1>Python Enhancement Proposals</h1> <ul class="breadcrumbs"> <li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> » </li> <li><a href="../pep-0000/">PEP Index</a> » </li> <li>PEP 750</li> </ul> <button id="colour-scheme-cycler" onClick="setColourScheme(nextColourScheme())"> <svg aria-hidden="true" class="colour-scheme-icon-when-auto"><use href="#svg-sun-half"></use></svg> <svg aria-hidden="true" class="colour-scheme-icon-when-dark"><use href="#svg-moon"></use></svg> <svg aria-hidden="true" class="colour-scheme-icon-when-light"><use href="#svg-sun"></use></svg> <span class="visually-hidden">Toggle light / dark / auto colour theme</span> </button> </header> <article> <section id="pep-content"> <h1 class="page-title">PEP 750 – Template Strings</h1> <dl class="rfc2822 field-list simple"> <dt class="field-odd">Author<span class="colon">:</span></dt> <dd class="field-odd">Jim Baker <jim.baker at python.org>, Guido van Rossum <guido at python.org>, Paul Everitt <pauleveritt at me.com>, Koudai Aono <koxudaxi at gmail.com>, Lysandros Nikolaou <lisandrosnik at gmail.com>, Dave Peck <davepeck at davepeck.org></dd> <dt class="field-even">Discussions-To<span class="colon">:</span></dt> <dd class="field-even"><a class="reference external" href="https://discuss.python.org/t/71594">Discourse thread</a></dd> <dt class="field-odd">Status<span class="colon">:</span></dt> <dd class="field-odd"><abbr title="Proposal under active discussion and revision">Draft</abbr></dd> <dt class="field-even">Type<span class="colon">:</span></dt> <dd class="field-even"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd> <dt class="field-odd">Created<span class="colon">:</span></dt> <dd class="field-odd">08-Jul-2024</dd> <dt class="field-even">Python-Version<span class="colon">:</span></dt> <dd class="field-even">3.14</dd> <dt class="field-odd">Post-History<span class="colon">:</span></dt> <dd class="field-odd"><a class="reference external" href="https://discuss.python.org/t/60408" title="Discourse thread">09-Aug-2024</a>, <a class="reference external" href="https://discuss.python.org/t/60408/201" title="Discourse message">17-Oct-2024</a>, <a class="reference external" href="https://discuss.python.org/t/60408/226" title="Discourse message">21-Oct-2024</a>, <a class="reference external" href="https://discuss.python.org/t/71594" title="Discourse thread">18-Nov-2024</a></dd> </dl> <hr class="docutils" /> <section id="contents"> <details><summary>Table of Contents</summary><ul class="simple"> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#relationship-with-other-peps">Relationship With Other PEPs</a></li> <li><a class="reference internal" href="#motivation">Motivation</a></li> <li><a class="reference internal" href="#specification">Specification</a><ul> <li><a class="reference internal" href="#template-string-literals">Template String Literals</a></li> <li><a class="reference internal" href="#the-template-type">The <code class="docutils literal notranslate"><span class="pre">Template</span></code> Type</a></li> <li><a class="reference internal" href="#the-interpolation-type">The <code class="docutils literal notranslate"><span class="pre">Interpolation</span></code> Type</a></li> <li><a class="reference internal" href="#convenience-accessors-in-template">Convenience Accessors in <code class="docutils literal notranslate"><span class="pre">Template</span></code></a></li> <li><a class="reference internal" href="#processing-template-strings">Processing Template Strings</a></li> <li><a class="reference internal" href="#template-string-concatenation">Template String Concatenation</a></li> <li><a class="reference internal" href="#template-and-interpolation-equality">Template and Interpolation Equality</a></li> <li><a class="reference internal" href="#no-support-for-ordering">No Support for Ordering</a></li> <li><a class="reference internal" href="#support-for-the-debug-specifier">Support for the debug specifier (<code class="docutils literal notranslate"><span class="pre">=</span></code>)</a></li> <li><a class="reference internal" href="#raw-template-strings">Raw Template Strings</a></li> <li><a class="reference internal" href="#interpolation-expression-evaluation">Interpolation Expression Evaluation</a></li> <li><a class="reference internal" href="#exceptions">Exceptions</a></li> <li><a class="reference internal" href="#no-template-str-implementation">No <code class="docutils literal notranslate"><span class="pre">Template.__str__()</span></code> Implementation</a></li> </ul> </li> <li><a class="reference internal" href="#examples">Examples</a><ul> <li><a class="reference internal" href="#example-implementing-f-strings-with-t-strings">Example: Implementing f-strings with t-strings</a></li> <li><a class="reference internal" href="#example-structured-logging">Example: Structured Logging</a><ul> <li><a class="reference internal" href="#approach-1-custom-log-messages">Approach 1: Custom Log Messages</a></li> <li><a class="reference internal" href="#approach-2-custom-formatters">Approach 2: Custom Formatters</a></li> </ul> </li> <li><a class="reference internal" href="#example-html-templating">Example: HTML Templating</a></li> </ul> </li> <li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a></li> <li><a class="reference internal" href="#security-implications">Security Implications</a></li> <li><a class="reference internal" href="#how-to-teach-this">How To Teach This</a></li> <li><a class="reference internal" href="#why-another-templating-approach">Why another templating approach?</a></li> <li><a class="reference internal" href="#common-patterns-seen-in-processing-templates">Common Patterns Seen in Processing Templates</a><ul> <li><a class="reference internal" href="#structural-pattern-matching">Structural Pattern Matching</a></li> <li><a class="reference internal" href="#memoizing">Memoizing</a></li> <li><a class="reference internal" href="#parsing-to-intermediate-representations">Parsing to Intermediate Representations</a></li> <li><a class="reference internal" href="#context-sensitive-processing-of-interpolations">Context-sensitive Processing of Interpolations</a></li> <li><a class="reference internal" href="#nested-template-strings">Nested Template Strings</a></li> <li><a class="reference internal" href="#approaches-to-lazy-evaluation">Approaches to Lazy Evaluation</a></li> <li><a class="reference internal" href="#approaches-to-asynchronous-evaluation">Approaches to Asynchronous Evaluation</a></li> <li><a class="reference internal" href="#approaches-to-template-reuse">Approaches to Template Reuse</a></li> <li><a class="reference internal" href="#relation-to-format-strings">Relation to Format Strings</a></li> </ul> </li> <li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li> <li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul> <li><a class="reference internal" href="#arbitrary-string-literal-prefixes">Arbitrary String Literal Prefixes</a></li> <li><a class="reference internal" href="#delayed-evaluation-of-interpolations">Delayed Evaluation of Interpolations</a></li> <li><a class="reference internal" href="#making-template-and-interpolation-into-protocols">Making <code class="docutils literal notranslate"><span class="pre">Template</span></code> and <code class="docutils literal notranslate"><span class="pre">Interpolation</span></code> Into Protocols</a></li> <li><a class="reference internal" href="#overridden-eq-and-hash-for-template-and-interpolation">Overridden <code class="docutils literal notranslate"><span class="pre">__eq__</span></code> and <code class="docutils literal notranslate"><span class="pre">__hash__</span></code> for <code class="docutils literal notranslate"><span class="pre">Template</span></code> and <code class="docutils literal notranslate"><span class="pre">Interpolation</span></code></a></li> <li><a class="reference internal" href="#an-additional-decoded-type">An Additional <code class="docutils literal notranslate"><span class="pre">Decoded</span></code> Type</a></li> <li><a class="reference internal" href="#the-final-home-for-template-and-interpolation">The Final Home for <code class="docutils literal notranslate"><span class="pre">Template</span></code> and <code class="docutils literal notranslate"><span class="pre">Interpolation</span></code></a></li> <li><a class="reference internal" href="#enable-full-reconstruction-of-original-template-literal">Enable Full Reconstruction of Original Template Literal</a></li> <li><a class="reference internal" href="#disallowing-string-concatenation">Disallowing String Concatenation</a></li> <li><a class="reference internal" href="#arbitrary-conversion-values">Arbitrary Conversion Values</a></li> <li><a class="reference internal" href="#removing-conv-from-interpolation">Removing <code class="docutils literal notranslate"><span class="pre">conv</span></code> From <code class="docutils literal notranslate"><span class="pre">Interpolation</span></code></a></li> <li><a class="reference internal" href="#alternate-interpolation-symbols">Alternate Interpolation Symbols</a></li> <li><a class="reference internal" href="#alternate-layouts-for-template">Alternate Layouts for <code class="docutils literal notranslate"><span class="pre">Template</span></code></a></li> <li><a class="reference internal" href="#mechanism-to-describe-the-kind-of-template">Mechanism to Describe the “Kind” of Template</a></li> <li><a class="reference internal" href="#binary-template-strings">Binary Template Strings</a></li> </ul> </li> <li><a class="reference internal" href="#acknowledgements">Acknowledgements</a></li> <li><a class="reference internal" href="#copyright">Copyright</a></li> </ul> </details></section> <section id="abstract"> <h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2> <p>This PEP introduces template strings for custom string processing.</p> <p>Template strings are a generalization of f-strings, using a <code class="docutils literal notranslate"><span class="pre">t</span></code> in place of the <code class="docutils literal notranslate"><span class="pre">f</span></code> prefix. Instead of evaluating to <code class="docutils literal notranslate"><span class="pre">str</span></code>, t-strings evaluate to a new type, <code class="docutils literal notranslate"><span class="pre">Template</span></code>:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">template</span><span class="p">:</span> <span class="n">Template</span> <span class="o">=</span> <span class="n">t</span><span class="s2">"Hello </span><span class="si">{name}</span><span class="s2">"</span> </pre></div> </div> <p>Templates provide developers with access to the string and its interpolated values <em>before</em> they are combined. This brings native flexible string processing to the Python language and enables safety checks, web templating, domain-specific languages, and more.</p> </section> <section id="relationship-with-other-peps"> <h2><a class="toc-backref" href="#relationship-with-other-peps" role="doc-backlink">Relationship With Other PEPs</a></h2> <p>Python introduced f-strings in Python 3.6 with <a class="pep reference internal" href="../pep-0498/" title="PEP 498 – Literal String Interpolation">PEP 498</a>. The grammar was then formalized in <a class="pep reference internal" href="../pep-0701/" title="PEP 701 – Syntactic formalization of f-strings">PEP 701</a> which also lifted some restrictions. This PEP is based on PEP 701.</p> <p>At nearly the same time PEP 498 arrived, <a class="pep reference internal" href="../pep-0501/" title="PEP 501 – General purpose template literal strings">PEP 501</a> was written to provide “i-strings” – that is, “interpolation template strings”. The PEP was deferred pending further experience with f-strings. Work on this PEP was resumed by a different author in March 2023, introducing “t-strings” as template literal strings, and built atop PEP 701.</p> <p>The authors of this PEP consider it to be a generalization and simplification of the updated work in PEP 501. (That PEP has also recently been updated to reflect the new ideas in this PEP.)</p> </section> <section id="motivation"> <h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2> <p>Python f-strings are easy to use and very popular. Over time, however, developers have encountered limitations that make them <a class="reference external" href="https://docs.djangoproject.com/en/5.1/ref/utils/#django.utils.html.format_html">unsuitable for certain use cases</a>. In particular, f-strings provide no way to intercept and transform interpolated values before they are combined into a final string.</p> <p>As a result, incautious use of f-strings can lead to security vulnerabilities. For example, a user executing a SQL query with <a class="reference external" href="https://docs.python.org/3/library/sqlite3.html#module-sqlite3" title="(in Python v3.13)"><code class="docutils literal notranslate"><span class="pre">sqlite3</span></code></a> may be tempted to use an f-string to embed values into their SQL expression, which could lead to a <a class="reference external" href="https://en.wikipedia.org/wiki/SQL_injection">SQL injection attack</a>. Or, a developer building HTML may include unescaped user input in the string, leading to a <a class="reference external" href="https://en.wikipedia.org/wiki/Cross-site_scripting">cross-site scripting (XSS)</a> vulnerability.</p> <p>More broadly, the inability to transform interpolated values before they are combined into a final string limits the utility of f-strings in more complex string processing tasks.</p> <p>Template strings address these problems by providing developers with access to the string and its interpolated values.</p> <p>For example, imagine we want to generate some HTML. Using template strings, we can define an <code class="docutils literal notranslate"><span class="pre">html()</span></code> function that allows us to automatically sanitize content:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">evil</span> <span class="o">=</span> <span class="s2">"<script>alert('evil')</script>"</span> <span class="n">template</span> <span class="o">=</span> <span class="n">t</span><span class="s2">"<p></span><span class="si">{evil}</span><span class="s2"></p>"</span> <span class="k">assert</span> <span class="n">html</span><span class="p">(</span><span class="n">template</span><span class="p">)</span> <span class="o">==</span> <span class="s2">"<p>&lt;script&gt;alert('evil')&lt;/script&gt;</p>"</span> </pre></div> </div> <p>Likewise, our hypothetical <code class="docutils literal notranslate"><span class="pre">html()</span></code> function can make it easy for developers to add attributes to HTML elements using a dictionary:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">attributes</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"src"</span><span class="p">:</span> <span class="s2">"shrubbery.jpg"</span><span class="p">,</span> <span class="s2">"alt"</span><span class="p">:</span> <span class="s2">"looks nice"</span><span class="p">}</span> <span class="n">template</span> <span class="o">=</span> <span class="n">t</span><span class="s2">"<img </span><span class="si">{attributes}</span><span class="s2"> />"</span> <span class="k">assert</span> <span class="n">html</span><span class="p">(</span><span class="n">template</span><span class="p">)</span> <span class="o">==</span> <span class="s1">'<img src="shrubbery.jpg" alt="looks nice" />'</span> </pre></div> </div> <p>Neither of these examples is possible with f-strings. By providing a mechanism to intercept and transform interpolated values, template strings enable a wide range of string processing use cases.</p> </section> <section id="specification"> <h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2> <section id="template-string-literals"> <h3><a class="toc-backref" href="#template-string-literals" role="doc-backlink">Template String Literals</a></h3> <p>This PEP introduces a new string prefix, <code class="docutils literal notranslate"><span class="pre">t</span></code>, to define template string literals. These literals resolve to a new type, <code class="docutils literal notranslate"><span class="pre">Template</span></code>, found in the standard library module <code class="docutils literal notranslate"><span class="pre"><<TBD>></span></code>.</p> <p>The following code creates a <code class="docutils literal notranslate"><span class="pre">Template</span></code> instance:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">TBD</span><span class="w"> </span><span class="kn">import</span> <span class="n">Template</span> <span class="n">template</span> <span class="o">=</span> <span class="n">t</span><span class="s2">"This is a template string."</span> <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">template</span><span class="p">,</span> <span class="n">Template</span><span class="p">)</span> </pre></div> </div> <p>Template string literals support the full syntax of <a class="pep reference internal" href="../pep-0701/" title="PEP 701 – Syntactic formalization of f-strings">PEP 701</a>. This includes the ability to nest template strings within interpolations, as well as the ability to use all valid quote marks (<code class="docutils literal notranslate"><span class="pre">'</span></code>, <code class="docutils literal notranslate"><span class="pre">"</span></code>, <code class="docutils literal notranslate"><span class="pre">'''</span></code>, and <code class="docutils literal notranslate"><span class="pre">"""</span></code>). Like other string prefixes, the <code class="docutils literal notranslate"><span class="pre">t</span></code> prefix must immediately precede the quote. Like f-strings, both lowercase <code class="docutils literal notranslate"><span class="pre">t</span></code> and uppercase <code class="docutils literal notranslate"><span class="pre">T</span></code> prefixes are supported. Like f-strings, t-strings may not be combined with <code class="docutils literal notranslate"><span class="pre">u</span></code> or the <code class="docutils literal notranslate"><span class="pre">b</span></code> prefix.</p> <p>Additionally, f-strings and t-strings cannot be combined, so the <code class="docutils literal notranslate"><span class="pre">ft</span></code> prefix is invalid. t-strings <em>may</em> be combined with the <code class="docutils literal notranslate"><span class="pre">r</span></code> prefix; see the <a class="reference internal" href="#raw-template-strings">Raw Template Strings</a> section below for more information.</p> </section> <section id="the-template-type"> <h3><a class="toc-backref" href="#the-template-type" role="doc-backlink">The <code class="docutils literal notranslate"><span class="pre">Template</span></code> Type</a></h3> <p>Template strings evaluate to an instance of a new immutable type, <code class="docutils literal notranslate"><span class="pre"><<TBD>>.Template</span></code>:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">Template</span><span class="p">:</span> <span class="n">strings</span><span class="p">:</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="o">...</span><span class="p">]</span> <span class="w"> </span><span class="sd">"""</span> <span class="sd"> A non-empty tuple of the string parts of the template,</span> <span class="sd"> with N+1 items, where N is the number of interpolations</span> <span class="sd"> in the template.</span> <span class="sd"> """</span> <span class="n">interpolations</span><span class="p">:</span> <span class="nb">tuple</span><span class="p">[</span><span class="n">Interpolation</span><span class="p">,</span> <span class="o">...</span><span class="p">]</span> <span class="w"> </span><span class="sd">"""</span> <span class="sd"> A tuple of the interpolation parts of the template.</span> <span class="sd"> This will be an empty tuple if there are no interpolations.</span> <span class="sd"> """</span> <span class="k">def</span><span class="w"> </span><span class="fm">__new__</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="n">Interpolation</span><span class="p">):</span> <span class="w"> </span><span class="sd">"""</span> <span class="sd"> Create a new Template instance.</span> <span class="sd"> Arguments can be provided in any order.</span> <span class="sd"> """</span> <span class="o">...</span> <span class="nd">@property</span> <span class="k">def</span><span class="w"> </span><span class="nf">values</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">object</span><span class="p">,</span> <span class="o">...</span><span class="p">]:</span> <span class="w"> </span><span class="sd">"""</span> <span class="sd"> Return a tuple of the `value` attributes of each Interpolation</span> <span class="sd"> in the template.</span> <span class="sd"> This will be an empty tuple if there are no interpolations.</span> <span class="sd"> """</span> <span class="o">...</span> <span class="k">def</span><span class="w"> </span><span class="fm">__iter__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">Iterator</span><span class="p">[</span><span class="nb">str</span> <span class="o">|</span> <span class="n">Interpolation</span><span class="p">]:</span> <span class="w"> </span><span class="sd">"""</span> <span class="sd"> Iterate over the string parts and interpolations in the template.</span> <span class="sd"> These may appear in any order. Empty strings will not be included.</span> <span class="sd"> """</span> <span class="o">...</span> </pre></div> </div> <p>The <code class="docutils literal notranslate"><span class="pre">strings</span></code> and <code class="docutils literal notranslate"><span class="pre">interpolations</span></code> attributes provide access to the string parts and any interpolations in the literal:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">name</span> <span class="o">=</span> <span class="s2">"World"</span> <span class="n">template</span> <span class="o">=</span> <span class="n">t</span><span class="s2">"Hello </span><span class="si">{name}</span><span class="s2">"</span> <span class="k">assert</span> <span class="n">template</span><span class="o">.</span><span class="n">strings</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s2">"Hello "</span> <span class="k">assert</span> <span class="n">template</span><span class="o">.</span><span class="n">interpolations</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">value</span> <span class="o">==</span> <span class="s2">"World"</span> </pre></div> </div> </section> <section id="the-interpolation-type"> <h3><a class="toc-backref" href="#the-interpolation-type" role="doc-backlink">The <code class="docutils literal notranslate"><span class="pre">Interpolation</span></code> Type</a></h3> <p>The <code class="docutils literal notranslate"><span class="pre">Interpolation</span></code> type represents an expression inside a template string. Like <code class="docutils literal notranslate"><span class="pre">Template</span></code>, it is a new class found in the <code class="docutils literal notranslate"><span class="pre"><<TBD>></span></code> module:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">Interpolation</span><span class="p">:</span> <span class="n">value</span><span class="p">:</span> <span class="nb">object</span> <span class="n">expr</span><span class="p">:</span> <span class="nb">str</span> <span class="n">conv</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="s2">"a"</span><span class="p">,</span> <span class="s2">"r"</span><span class="p">,</span> <span class="s2">"s"</span><span class="p">]</span> <span class="o">|</span> <span class="kc">None</span> <span class="n">format_spec</span><span class="p">:</span> <span class="nb">str</span> <span class="n">__match_args__</span> <span class="o">=</span> <span class="p">(</span><span class="s2">"value"</span><span class="p">,</span> <span class="s2">"expr"</span><span class="p">,</span> <span class="s2">"conv"</span><span class="p">,</span> <span class="s2">"format_spec"</span><span class="p">)</span> <span class="k">def</span><span class="w"> </span><span class="fm">__new__</span><span class="p">(</span> <span class="bp">cls</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">object</span><span class="p">,</span> <span class="n">expr</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">conv</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="s2">"a"</span><span class="p">,</span> <span class="s2">"r"</span><span class="p">,</span> <span class="s2">"s"</span><span class="p">]</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="n">format_spec</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">""</span><span class="p">,</span> <span class="p">):</span> <span class="o">...</span> </pre></div> </div> <p>The <code class="docutils literal notranslate"><span class="pre">Interpolation</span></code> type is shallow immutable. Its attributes cannot be reassigned.</p> <p>The <code class="docutils literal notranslate"><span class="pre">value</span></code> attribute is the evaluated result of the interpolation:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">name</span> <span class="o">=</span> <span class="s2">"World"</span> <span class="n">template</span> <span class="o">=</span> <span class="n">t</span><span class="s2">"Hello </span><span class="si">{name}</span><span class="s2">"</span> <span class="k">assert</span> <span class="n">template</span><span class="o">.</span><span class="n">interpolations</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">value</span> <span class="o">==</span> <span class="s2">"World"</span> </pre></div> </div> <p>The <code class="docutils literal notranslate"><span class="pre">expr</span></code> attribute is the <em>original text</em> of the interpolation:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">name</span> <span class="o">=</span> <span class="s2">"World"</span> <span class="n">template</span> <span class="o">=</span> <span class="n">t</span><span class="s2">"Hello </span><span class="si">{name}</span><span class="s2">"</span> <span class="k">assert</span> <span class="n">template</span><span class="o">.</span><span class="n">interpolations</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">expr</span> <span class="o">==</span> <span class="s2">"name"</span> </pre></div> </div> <p>We expect that the <code class="docutils literal notranslate"><span class="pre">expr</span></code> attribute will not be used in most template processing code. It is provided for completeness and for use in debugging and introspection. See both the <a class="reference internal" href="#common-patterns-seen-in-processing-templates">Common Patterns Seen in Processing Templates</a> section and the <a class="reference internal" href="#examples">Examples</a> section for more information on how to process template strings.</p> <p>The <code class="docutils literal notranslate"><span class="pre">conv</span></code> attribute is the <a class="reference external" href="https://docs.python.org/3/library/string.html#formatstrings" title="(in Python v3.13)"><span class="xref std std-ref">optional conversion</span></a> to be used, one of <code class="docutils literal notranslate"><span class="pre">r</span></code>, <code class="docutils literal notranslate"><span class="pre">s</span></code>, and <code class="docutils literal notranslate"><span class="pre">a</span></code>, corresponding to <code class="docutils literal notranslate"><span class="pre">repr()</span></code>, <code class="docutils literal notranslate"><span class="pre">str()</span></code>, and <code class="docutils literal notranslate"><span class="pre">ascii()</span></code> conversions. As with f-strings, no other conversions are supported:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">name</span> <span class="o">=</span> <span class="s2">"World"</span> <span class="n">template</span> <span class="o">=</span> <span class="n">t</span><span class="s2">"Hello </span><span class="si">{name!r}</span><span class="s2">"</span> <span class="k">assert</span> <span class="n">template</span><span class="o">.</span><span class="n">interpolations</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">conv</span> <span class="o">==</span> <span class="s2">"r"</span> </pre></div> </div> <p>If no conversion is provided, <code class="docutils literal notranslate"><span class="pre">conv</span></code> is <code class="docutils literal notranslate"><span class="pre">None</span></code>.</p> <p>The <code class="docutils literal notranslate"><span class="pre">format_spec</span></code> attribute is the <a class="reference external" href="https://docs.python.org/3/library/string.html#formatspec" title="(in Python v3.13)"><span class="xref std std-ref">format specification</span></a>. As with f-strings, this is an arbitrary string that defines how to present the value:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">value</span> <span class="o">=</span> <span class="mi">42</span> <span class="n">template</span> <span class="o">=</span> <span class="n">t</span><span class="s2">"Value: </span><span class="si">{value:.2f}</span><span class="s2">"</span> <span class="k">assert</span> <span class="n">template</span><span class="o">.</span><span class="n">interpolations</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">format_spec</span> <span class="o">==</span> <span class="s2">".2f"</span> </pre></div> </div> <p>Format specifications in f-strings can themselves contain interpolations. This is permitted in template strings as well; <code class="docutils literal notranslate"><span class="pre">format_spec</span></code> is set to the eagerly evaluated result:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">value</span> <span class="o">=</span> <span class="mi">42</span> <span class="n">precision</span> <span class="o">=</span> <span class="mi">2</span> <span class="n">template</span> <span class="o">=</span> <span class="n">t</span><span class="s2">"Value: {value:.</span><span class="si">{precision}</span><span class="s2">f}"</span> <span class="k">assert</span> <span class="n">template</span><span class="o">.</span><span class="n">interpolations</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">format_spec</span> <span class="o">==</span> <span class="s2">".2f"</span> </pre></div> </div> <p>If no format specification is provided, <code class="docutils literal notranslate"><span class="pre">format_spec</span></code> defaults to an empty string (<code class="docutils literal notranslate"><span class="pre">""</span></code>). This matches the <code class="docutils literal notranslate"><span class="pre">format_spec</span></code> parameter of Python’s <a class="reference external" href="https://docs.python.org/3/library/functions.html#format" title="(in Python v3.13)"><code class="docutils literal notranslate"><span class="pre">format()</span></code></a> built-in.</p> <p>Unlike f-strings, it is up to code that processes the template to determine how to interpret the <code class="docutils literal notranslate"><span class="pre">conv</span></code> and <code class="docutils literal notranslate"><span class="pre">format_spec</span></code> attributes. Such code is not required to use these attributes, but when present they should be respected, and to the extent possible match the behavior of f-strings. It would be surprising if, for example, a template string that uses <code class="docutils literal notranslate"><span class="pre">{value:.2f}</span></code> did not round the value to two decimal places when processed.</p> </section> <section id="convenience-accessors-in-template"> <h3><a class="toc-backref" href="#convenience-accessors-in-template" role="doc-backlink">Convenience Accessors in <code class="docutils literal notranslate"><span class="pre">Template</span></code></a></h3> <p>The <code class="docutils literal notranslate"><span class="pre">Template.values</span></code> property is equivalent to:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nd">@property</span> <span class="k">def</span><span class="w"> </span><span class="nf">values</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">object</span><span class="p">,</span> <span class="o">...</span><span class="p">]:</span> <span class="k">return</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">i</span><span class="o">.</span><span class="n">value</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">interpolations</span><span class="p">)</span> </pre></div> </div> <p>The <code class="docutils literal notranslate"><span class="pre">Template.__iter__()</span></code> method is equivalent to:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="fm">__iter__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">Iterator</span><span class="p">[</span><span class="nb">str</span> <span class="o">|</span> <span class="n">Interpolation</span><span class="p">]:</span> <span class="k">for</span> <span class="n">s</span><span class="p">,</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">zip_longest</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">strings</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">interpolations</span><span class="p">):</span> <span class="k">if</span> <span class="n">s</span><span class="p">:</span> <span class="k">yield</span> <span class="n">s</span> <span class="k">if</span> <span class="n">i</span><span class="p">:</span> <span class="k">yield</span> <span class="n">i</span> </pre></div> </div> </section> <section id="processing-template-strings"> <h3><a class="toc-backref" href="#processing-template-strings" role="doc-backlink">Processing Template Strings</a></h3> <p>Developers can write arbitrary code to process template strings. For example, the following function renders static parts of the template in lowercase and interpolations in uppercase:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">TBD</span><span class="w"> </span><span class="kn">import</span> <span class="n">Template</span><span class="p">,</span> <span class="n">Interpolation</span> <span class="k">def</span><span class="w"> </span><span class="nf">lower_upper</span><span class="p">(</span><span class="n">template</span><span class="p">:</span> <span class="n">Template</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span> <span class="w"> </span><span class="sd">"""Render static parts lowercased and interpolations uppercased."""</span> <span class="n">parts</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span> <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">template</span><span class="p">:</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="n">Interpolation</span><span class="p">):</span> <span class="n">parts</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">item</span><span class="o">.</span><span class="n">value</span><span class="p">)</span><span class="o">.</span><span class="n">upper</span><span class="p">())</span> <span class="k">else</span><span class="p">:</span> <span class="n">parts</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">item</span><span class="o">.</span><span class="n">lower</span><span class="p">())</span> <span class="k">return</span> <span class="s2">""</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">parts</span><span class="p">)</span> <span class="n">name</span> <span class="o">=</span> <span class="s2">"world"</span> <span class="k">assert</span> <span class="n">lower_upper</span><span class="p">(</span><span class="n">t</span><span class="s2">"HELLO </span><span class="si">{name}</span><span class="s2">"</span><span class="p">)</span> <span class="o">==</span> <span class="s2">"hello WORLD"</span> </pre></div> </div> <p>There is no requirement that template strings are processed in any particular way. Code that processes templates has no obligation to return a string. Template strings are a flexible, general-purpose feature.</p> <p>See the <a class="reference internal" href="#common-patterns-seen-in-processing-templates">Common Patterns Seen in Processing Templates</a> section for more information on how to process template strings. See the <a class="reference internal" href="#examples">Examples</a> section for detailed working examples.</p> </section> <section id="template-string-concatenation"> <h3><a class="toc-backref" href="#template-string-concatenation" role="doc-backlink">Template String Concatenation</a></h3> <p>Template strings support explicit concatenation using <code class="docutils literal notranslate"><span class="pre">+</span></code>. Concatenation is supported for two <code class="docutils literal notranslate"><span class="pre">Template</span></code> instances as well as for a <code class="docutils literal notranslate"><span class="pre">Template</span></code> instance and a <code class="docutils literal notranslate"><span class="pre">str</span></code>:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">name</span> <span class="o">=</span> <span class="s2">"World"</span> <span class="n">template</span> <span class="o">=</span> <span class="n">t</span><span class="s2">"</span><span class="si">{name}</span><span class="s2">"</span> <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">t</span><span class="s2">"Hello "</span> <span class="o">+</span> <span class="n">template</span><span class="p">,</span> <span class="n">Template</span><span class="p">)</span> <span class="k">assert</span> <span class="p">(</span><span class="n">t</span><span class="s2">"Hello "</span> <span class="o">+</span> <span class="n">template</span><span class="p">)</span><span class="o">.</span><span class="n">strings</span> <span class="o">==</span> <span class="p">(</span><span class="s2">"Hello "</span><span class="p">,</span> <span class="s2">""</span><span class="p">)</span> <span class="k">assert</span> <span class="p">(</span><span class="n">t</span><span class="s2">"Hello "</span> <span class="o">+</span> <span class="n">template</span><span class="p">)</span><span class="o">.</span><span class="n">interpolations</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">value</span> <span class="o">==</span> <span class="s2">"World"</span> <span class="k">assert</span> <span class="nb">isinstance</span><span class="p">(</span><span class="s2">"Hello "</span> <span class="o">+</span> <span class="n">template</span><span class="p">,</span> <span class="n">Template</span><span class="p">)</span> <span class="k">assert</span> <span class="p">(</span><span class="s2">"Hello "</span> <span class="o">+</span> <span class="n">template</span><span class="p">)</span><span class="o">.</span><span class="n">strings</span> <span class="o">==</span> <span class="p">(</span><span class="s2">"Hello "</span><span class="p">,</span> <span class="s2">""</span><span class="p">)</span> <span class="k">assert</span> <span class="p">(</span><span class="s2">"Hello "</span> <span class="o">+</span> <span class="n">template</span><span class="p">)</span><span class="o">.</span><span class="n">interpolations</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">value</span> <span class="o">==</span> <span class="s2">"World"</span> </pre></div> </div> <p>Concatenation of templates is “viral”: the concatenation of a <code class="docutils literal notranslate"><span class="pre">Template</span></code> and a <code class="docutils literal notranslate"><span class="pre">str</span></code> always results in a <code class="docutils literal notranslate"><span class="pre">Template</span></code> instance.</p> <p>Python’s implicit concatenation syntax is also supported. The following code will work as expected:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">name</span> <span class="o">=</span> <span class="s2">"World"</span> <span class="k">assert</span> <span class="p">(</span><span class="n">t</span><span class="s2">"Hello "</span> <span class="n">t</span><span class="s2">"World"</span><span class="p">)</span><span class="o">.</span><span class="n">strings</span> <span class="o">==</span> <span class="p">(</span><span class="s2">"Hello World"</span><span class="p">,)</span> <span class="k">assert</span> <span class="p">(</span><span class="s2">"Hello "</span> <span class="n">t</span><span class="s2">"World"</span><span class="p">)</span><span class="o">.</span><span class="n">strings</span> <span class="o">==</span> <span class="p">(</span><span class="s2">"Hello World"</span><span class="p">,)</span> </pre></div> </div> <p>The <code class="docutils literal notranslate"><span class="pre">Template</span></code> type supports the <code class="docutils literal notranslate"><span class="pre">__add__()</span></code> and <code class="docutils literal notranslate"><span class="pre">__radd__()</span></code> methods between two <code class="docutils literal notranslate"><span class="pre">Template</span></code> instances and between a <code class="docutils literal notranslate"><span class="pre">Template</span></code> instance and a <code class="docutils literal notranslate"><span class="pre">str</span></code>.</p> </section> <section id="template-and-interpolation-equality"> <h3><a class="toc-backref" href="#template-and-interpolation-equality" role="doc-backlink">Template and Interpolation Equality</a></h3> <p><code class="docutils literal notranslate"><span class="pre">Template</span></code> and <code class="docutils literal notranslate"><span class="pre">Interpolation</span></code> instances compare with object identity (<code class="docutils literal notranslate"><span class="pre">is</span></code>).</p> <p><code class="docutils literal notranslate"><span class="pre">Template</span></code> instances are intended to be used by template processing code, which may return a string or any other type. Those types can provide their own equality semantics as needed.</p> </section> <section id="no-support-for-ordering"> <h3><a class="toc-backref" href="#no-support-for-ordering" role="doc-backlink">No Support for Ordering</a></h3> <p>The <code class="docutils literal notranslate"><span class="pre">Template</span></code> and <code class="docutils literal notranslate"><span class="pre">Interpolation</span></code> types do not support ordering. This is unlike all other string literal types in Python, which support lexicographic ordering. Because interpolations can contain arbitrary values, there is no natural ordering for them. As a result, neither the <code class="docutils literal notranslate"><span class="pre">Template</span></code> nor the <code class="docutils literal notranslate"><span class="pre">Interpolation</span></code> type implements the standard comparison methods.</p> </section> <section id="support-for-the-debug-specifier"> <h3><a class="toc-backref" href="#support-for-the-debug-specifier" role="doc-backlink">Support for the debug specifier (<code class="docutils literal notranslate"><span class="pre">=</span></code>)</a></h3> <p>The debug specifier, <code class="docutils literal notranslate"><span class="pre">=</span></code>, is supported in template strings and behaves similarly to how it behaves in f-strings, though due to limitations of the implementation there is a slight difference.</p> <p>In particular, <code class="docutils literal notranslate"><span class="pre">t'{expr=}'</span></code> is treated as <code class="docutils literal notranslate"><span class="pre">t'expr={expr!r}'</span></code>:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">name</span> <span class="o">=</span> <span class="s2">"World"</span> <span class="n">template</span> <span class="o">=</span> <span class="n">t</span><span class="s2">"Hello {name=}"</span> <span class="k">assert</span> <span class="n">template</span><span class="o">.</span><span class="n">strings</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s2">"Hello name="</span> <span class="k">assert</span> <span class="n">template</span><span class="o">.</span><span class="n">interpolations</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">value</span> <span class="o">==</span> <span class="s2">"World"</span> <span class="k">assert</span> <span class="n">template</span><span class="o">.</span><span class="n">interpolations</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">conv</span> <span class="o">==</span> <span class="s2">"r"</span> </pre></div> </div> <p>If a separate format string is also provided, <code class="docutils literal notranslate"><span class="pre">t'{expr=:fmt}</span></code> is treated instead as <code class="docutils literal notranslate"><span class="pre">t'expr={expr!s:fmt}'</span></code>.</p> <p>Whitespace is preserved in the debug specifier, so <code class="docutils literal notranslate"><span class="pre">t'{expr</span> <span class="pre">=</span> <span class="pre">}'</span></code> is treated as <code class="docutils literal notranslate"><span class="pre">t'expr</span> <span class="pre">=</span> <span class="pre">{expr!r}'</span></code>.</p> </section> <section id="raw-template-strings"> <h3><a class="toc-backref" href="#raw-template-strings" role="doc-backlink">Raw Template Strings</a></h3> <p>Raw template strings are supported using the <code class="docutils literal notranslate"><span class="pre">rt</span></code> (or <code class="docutils literal notranslate"><span class="pre">tr</span></code>) prefix:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">trade</span> <span class="o">=</span> <span class="s1">'shrubberies'</span> <span class="n">template</span> <span class="o">=</span> <span class="n">rt</span><span class="s1">'Did you say "</span><span class="si">{trade}</span><span class="s1">"?</span><span class="se">\n</span><span class="s1">'</span> <span class="k">assert</span> <span class="n">template</span><span class="o">.</span><span class="n">strings</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="sa">r</span><span class="s1">'Did you say "'</span> <span class="k">assert</span> <span class="n">template</span><span class="o">.</span><span class="n">strings</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="sa">r</span><span class="s1">'"?\n'</span> </pre></div> </div> <p>In this example, the <code class="docutils literal notranslate"><span class="pre">\n</span></code> is treated as two separate characters (a backslash followed by ‘n’) rather than a newline character. This is consistent with Python’s raw string behavior.</p> <p>As with regular template strings, interpolations in raw template strings are processed normally, allowing for the combination of raw string behavior and dynamic content.</p> </section> <section id="interpolation-expression-evaluation"> <h3><a class="toc-backref" href="#interpolation-expression-evaluation" role="doc-backlink">Interpolation Expression Evaluation</a></h3> <p>Expression evaluation for interpolations is the same as in <a class="pep reference internal" href="../pep-0498/#expression-evaluation" title="PEP 498 – Literal String Interpolation § Expression evaluation">PEP 498</a>:</p> <blockquote> <div>The expressions that are extracted from the string are evaluated in the context where the template string appeared. This means the expression has full access to its lexical scope, including local and global variables. Any valid Python expression can be used, including function and method calls.</div></blockquote> <p>Template strings are evaluated eagerly from left to right, just like f-strings. This means that interpolations are evaluated immediately when the template string is processed, not deferred or wrapped in lambdas.</p> </section> <section id="exceptions"> <h3><a class="toc-backref" href="#exceptions" role="doc-backlink">Exceptions</a></h3> <p>Exceptions raised in t-string literals are the same as those raised in f-string literals.</p> </section> <section id="no-template-str-implementation"> <h3><a class="toc-backref" href="#no-template-str-implementation" role="doc-backlink">No <code class="docutils literal notranslate"><span class="pre">Template.__str__()</span></code> Implementation</a></h3> <p>The <code class="docutils literal notranslate"><span class="pre">Template</span></code> type does not provide a specialized <code class="docutils literal notranslate"><span class="pre">__str__()</span></code> implementation.</p> <p>This is because <code class="docutils literal notranslate"><span class="pre">Template</span></code> instances are intended to be used by template processing code, which may return a string or any other type. There is no canonical way to convert a Template to a string.</p> <p>The <code class="docutils literal notranslate"><span class="pre">Template</span></code> and <code class="docutils literal notranslate"><span class="pre">Interpolation</span></code> types both provide useful <code class="docutils literal notranslate"><span class="pre">__repr__()</span></code> implementations.</p> </section> </section> <section id="examples"> <h2><a class="toc-backref" href="#examples" role="doc-backlink">Examples</a></h2> <p>All examples in this section of the PEP have fully tested reference implementations available in the public <a class="reference external" href="https://github.com/davepeck/pep750-examples">pep750-examples</a> git repository.</p> <section id="example-implementing-f-strings-with-t-strings"> <h3><a class="toc-backref" href="#example-implementing-f-strings-with-t-strings" role="doc-backlink">Example: Implementing f-strings with t-strings</a></h3> <p>It is easy to “implement” f-strings using t-strings. That is, we can write a function <code class="docutils literal notranslate"><span class="pre">f(template:</span> <span class="pre">Template)</span> <span class="pre">-></span> <span class="pre">str</span></code> that processes a <code class="docutils literal notranslate"><span class="pre">Template</span></code> in much the same way as an f-string literal, returning the same result:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">name</span> <span class="o">=</span> <span class="s2">"World"</span> <span class="n">value</span> <span class="o">=</span> <span class="mi">42</span> <span class="n">templated</span> <span class="o">=</span> <span class="n">t</span><span class="s2">"Hello </span><span class="si">{name!r}</span><span class="s2">, value: </span><span class="si">{value:.2f}</span><span class="s2">"</span> <span class="n">formatted</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"Hello </span><span class="si">{</span><span class="n">name</span><span class="si">!r}</span><span class="s2">, value: </span><span class="si">{</span><span class="n">value</span><span class="si">:</span><span class="s2">.2f</span><span class="si">}</span><span class="s2">"</span> <span class="k">assert</span> <span class="n">f</span><span class="p">(</span><span class="n">templated</span><span class="p">)</span> <span class="o">==</span> <span class="n">formatted</span> </pre></div> </div> <p>The <code class="docutils literal notranslate"><span class="pre">f()</span></code> function supports both conversion specifiers like <code class="docutils literal notranslate"><span class="pre">!r</span></code> and format specifiers like <code class="docutils literal notranslate"><span class="pre">:.2f</span></code>. The full code is fairly simple:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">TBD</span><span class="w"> </span><span class="kn">import</span> <span class="n">Template</span><span class="p">,</span> <span class="n">Interpolation</span> <span class="k">def</span><span class="w"> </span><span class="nf">convert</span><span class="p">(</span><span class="n">value</span><span class="p">:</span> <span class="nb">object</span><span class="p">,</span> <span class="n">conv</span><span class="p">:</span> <span class="n">Literal</span><span class="p">[</span><span class="s2">"a"</span><span class="p">,</span> <span class="s2">"r"</span><span class="p">,</span> <span class="s2">"s"</span><span class="p">]</span> <span class="o">|</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-></span> <span class="nb">object</span><span class="p">:</span> <span class="k">if</span> <span class="n">conv</span> <span class="o">==</span> <span class="s2">"a"</span><span class="p">:</span> <span class="k">return</span> <span class="n">ascii</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="k">elif</span> <span class="n">conv</span> <span class="o">==</span> <span class="s2">"r"</span><span class="p">:</span> <span class="k">return</span> <span class="nb">repr</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="k">elif</span> <span class="n">conv</span> <span class="o">==</span> <span class="s2">"s"</span><span class="p">:</span> <span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="k">return</span> <span class="n">value</span> <span class="k">def</span><span class="w"> </span><span class="nf">f</span><span class="p">(</span><span class="n">template</span><span class="p">:</span> <span class="n">Template</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span> <span class="n">parts</span> <span class="o">=</span> <span class="p">[]</span> <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">template</span><span class="p">:</span> <span class="k">match</span> <span class="n">item</span><span class="p">:</span> <span class="k">case</span> <span class="nb">str</span><span class="p">()</span> <span class="k">as</span> <span class="n">s</span><span class="p">:</span> <span class="n">parts</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="k">case</span><span class="w"> </span><span class="n">Interpolation</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="k">_</span><span class="p">,</span> <span class="n">conv</span><span class="p">,</span> <span class="n">format_spec</span><span class="p">):</span> <span class="n">value</span> <span class="o">=</span> <span class="n">convert</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="n">conv</span><span class="p">)</span> <span class="n">value</span> <span class="o">=</span> <span class="nb">format</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="n">format_spec</span><span class="p">)</span> <span class="n">parts</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="k">return</span> <span class="s2">""</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">parts</span><span class="p">)</span> </pre></div> </div> <div class="admonition note"> <p class="admonition-title">Note</p> <p>Example code</p> <p>See <a class="reference external" href="https://github.com/davepeck/pep750-examples/blob/main/pep/fstring.py">fstring.py</a> and <a class="reference external" href="https://github.com/davepeck/pep750-examples/blob/main/pep/test_fstring.py">test_fstring.py</a>.</p> </div> </section> <section id="example-structured-logging"> <h3><a class="toc-backref" href="#example-structured-logging" role="doc-backlink">Example: Structured Logging</a></h3> <p>Structured logging allows developers to log data in machine-readable formats like JSON. With t-strings, developers can easily log structured data alongside human-readable messages using just a single log statement.</p> <p>We present two different approaches to implementing structured logging with template strings.</p> <section id="approach-1-custom-log-messages"> <h4><a class="toc-backref" href="#approach-1-custom-log-messages" role="doc-backlink">Approach 1: Custom Log Messages</a></h4> <p>The <a class="reference external" href="https://docs.python.org/3/howto/logging-cookbook.html#logging-cookbook" title="(in Python v3.13)"><span class="xref std std-ref">Python Logging Cookbook</span></a> has a short section on <a class="reference external" href="https://docs.python.org/3/howto/logging-cookbook.html#implementing-structured-logging">how to implement structured logging</a>.</p> <p>The logging cookbook suggests creating a new “message” class, <code class="docutils literal notranslate"><span class="pre">StructuredMessage</span></code>, that is constructed with a simple text message and a separate dictionary of values:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">message</span> <span class="o">=</span> <span class="n">StructuredMessage</span><span class="p">(</span><span class="s2">"user action"</span><span class="p">,</span> <span class="p">{</span> <span class="s2">"action"</span><span class="p">:</span> <span class="s2">"traded"</span><span class="p">,</span> <span class="s2">"amount"</span><span class="p">:</span> <span class="mi">42</span><span class="p">,</span> <span class="s2">"item"</span><span class="p">:</span> <span class="s2">"shrubs"</span> <span class="p">})</span> <span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="n">message</span><span class="p">)</span> <span class="c1"># Outputs:</span> <span class="c1"># user action >>> {"action": "traded", "amount": 42, "item": "shrubs"}</span> </pre></div> </div> <p>The <code class="docutils literal notranslate"><span class="pre">StructuredMessage.__str__()</span></code> method formats both the human-readable message <em>and</em> the values, combining them into a final string. (See the <a class="reference external" href="https://docs.python.org/3/howto/logging-cookbook.html#implementing-structured-logging">logging cookbook</a> for its full example.)</p> <p>We can implement an improved version of <code class="docutils literal notranslate"><span class="pre">StructuredMessage</span></code> using template strings:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span><span class="w"> </span><span class="nn">json</span> <span class="kn">from</span><span class="w"> </span><span class="nn">TBD</span><span class="w"> </span><span class="kn">import</span> <span class="n">Interpolation</span><span class="p">,</span> <span class="n">Template</span> <span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Mapping</span> <span class="k">class</span><span class="w"> </span><span class="nc">TemplateMessage</span><span class="p">:</span> <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">template</span><span class="p">:</span> <span class="n">Template</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">template</span> <span class="o">=</span> <span class="n">template</span> <span class="nd">@property</span> <span class="k">def</span><span class="w"> </span><span class="nf">message</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span> <span class="c1"># Use the f() function from the previous example</span> <span class="k">return</span> <span class="n">f</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">template</span><span class="p">)</span> <span class="nd">@property</span> <span class="k">def</span><span class="w"> </span><span class="nf">values</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="n">Mapping</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">object</span><span class="p">]:</span> <span class="k">return</span> <span class="p">{</span> <span class="n">item</span><span class="o">.</span><span class="n">expr</span><span class="p">:</span> <span class="n">item</span><span class="o">.</span><span class="n">value</span> <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">template</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="n">Interpolation</span><span class="p">)</span> <span class="p">}</span> <span class="k">def</span><span class="w"> </span><span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span> <span class="k">return</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">message</span><span class="si">}</span><span class="s2"> >>> </span><span class="si">{</span><span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">values</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span> <span class="n">_</span> <span class="o">=</span> <span class="n">TemplateMessage</span> <span class="c1"># optional, to improve readability</span> <span class="n">action</span><span class="p">,</span> <span class="n">amount</span><span class="p">,</span> <span class="n">item</span> <span class="o">=</span> <span class="s2">"traded"</span><span class="p">,</span> <span class="mi">42</span><span class="p">,</span> <span class="s2">"shrubs"</span> <span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="n">_</span><span class="p">(</span><span class="n">t</span><span class="s2">"User </span><span class="si">{action}</span><span class="s2">: </span><span class="si">{amount:.2f}</span><span class="s2"> </span><span class="si">{item}</span><span class="s2">"</span><span class="p">))</span> <span class="c1"># Outputs:</span> <span class="c1"># User traded: 42.00 shrubs >>> {"action": "traded", "amount": 42, "item": "shrubs"}</span> </pre></div> </div> <p>Template strings give us a more elegant way to define the custom message class. With template strings it is no longer necessary for developers to make sure that their format string and values dictionary are kept in sync; a single template string literal is all that is needed. The <code class="docutils literal notranslate"><span class="pre">TemplateMessage</span></code> implementation can automatically extract structured keys and values from the <code class="docutils literal notranslate"><span class="pre">Interpolation.expr</span></code> and <code class="docutils literal notranslate"><span class="pre">Interpolation.value</span></code> attributes, respectively.</p> </section> <section id="approach-2-custom-formatters"> <h4><a class="toc-backref" href="#approach-2-custom-formatters" role="doc-backlink">Approach 2: Custom Formatters</a></h4> <p>Custom messages are a reasonable approach to structured logging but can be a little awkward. To use them, developers must wrap every log message they write in a custom class. This can be easy to forget.</p> <p>An alternative approach is to define custom <code class="docutils literal notranslate"><span class="pre">logging.Formatter</span></code> classes. This approach is more flexible and allows for more control over the final output. In particular, it’s possible to take a single template string and output it in multiple formats (human-readable and JSON) to separate log streams.</p> <p>We define two simple formatters, a <code class="docutils literal notranslate"><span class="pre">MessageFormatter</span></code> for human-readable output and a <code class="docutils literal notranslate"><span class="pre">ValuesFormatter</span></code> for JSON output:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span><span class="w"> </span><span class="nn">json</span> <span class="kn">from</span><span class="w"> </span><span class="nn">logging</span><span class="w"> </span><span class="kn">import</span> <span class="n">Formatter</span><span class="p">,</span> <span class="n">LogRecord</span> <span class="kn">from</span><span class="w"> </span><span class="nn">TBD</span><span class="w"> </span><span class="kn">import</span> <span class="n">Interpolation</span><span class="p">,</span> <span class="n">Template</span> <span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Any</span><span class="p">,</span> <span class="n">Mapping</span> <span class="k">class</span><span class="w"> </span><span class="nc">MessageFormatter</span><span class="p">(</span><span class="n">Formatter</span><span class="p">):</span> <span class="k">def</span><span class="w"> </span><span class="nf">message</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">template</span><span class="p">:</span> <span class="n">Template</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span> <span class="c1"># Use the f() function from the previous example</span> <span class="k">return</span> <span class="n">f</span><span class="p">(</span><span class="n">template</span><span class="p">)</span> <span class="k">def</span><span class="w"> </span><span class="nf">format</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">record</span><span class="p">:</span> <span class="n">LogRecord</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span> <span class="n">msg</span> <span class="o">=</span> <span class="n">record</span><span class="o">.</span><span class="n">msg</span> <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">Template</span><span class="p">):</span> <span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">record</span><span class="p">)</span> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">message</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span> <span class="k">class</span><span class="w"> </span><span class="nc">ValuesFormatter</span><span class="p">(</span><span class="n">Formatter</span><span class="p">):</span> <span class="k">def</span><span class="w"> </span><span class="nf">values</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">template</span><span class="p">:</span> <span class="n">Template</span><span class="p">)</span> <span class="o">-></span> <span class="n">Mapping</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span> <span class="k">return</span> <span class="p">{</span> <span class="n">item</span><span class="o">.</span><span class="n">expr</span><span class="p">:</span> <span class="n">item</span><span class="o">.</span><span class="n">value</span> <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">template</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="n">Interpolation</span><span class="p">)</span> <span class="p">}</span> <span class="k">def</span><span class="w"> </span><span class="nf">format</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">record</span><span class="p">:</span> <span class="n">LogRecord</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span> <span class="n">msg</span> <span class="o">=</span> <span class="n">record</span><span class="o">.</span><span class="n">msg</span> <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">Template</span><span class="p">):</span> <span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">record</span><span class="p">)</span> <span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">values</span><span class="p">(</span><span class="n">msg</span><span class="p">))</span> </pre></div> </div> <p>We can then use these formatters when configuring our logger:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span><span class="w"> </span><span class="nn">logging</span> <span class="kn">import</span><span class="w"> </span><span class="nn">sys</span> <span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="vm">__name__</span><span class="p">)</span> <span class="n">message_handler</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">StreamHandler</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="p">)</span> <span class="n">message_handler</span><span class="o">.</span><span class="n">setFormatter</span><span class="p">(</span><span class="n">MessageFormatter</span><span class="p">())</span> <span class="n">logger</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">message_handler</span><span class="p">)</span> <span class="n">values_handler</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">StreamHandler</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">stderr</span><span class="p">)</span> <span class="n">values_handler</span><span class="o">.</span><span class="n">setFormatter</span><span class="p">(</span><span class="n">ValuesFormatter</span><span class="p">())</span> <span class="n">logger</span><span class="o">.</span><span class="n">addHandler</span><span class="p">(</span><span class="n">values_handler</span><span class="p">)</span> <span class="n">action</span><span class="p">,</span> <span class="n">amount</span><span class="p">,</span> <span class="n">item</span> <span class="o">=</span> <span class="s2">"traded"</span><span class="p">,</span> <span class="mi">42</span><span class="p">,</span> <span class="s2">"shrubs"</span> <span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="n">t</span><span class="s2">"User </span><span class="si">{action}</span><span class="s2">: </span><span class="si">{amount:.2f}</span><span class="s2"> </span><span class="si">{item}</span><span class="s2">"</span><span class="p">)</span> <span class="c1"># Outputs to sys.stdout:</span> <span class="c1"># User traded: 42.00 shrubs</span> <span class="c1"># At the same time, outputs to sys.stderr:</span> <span class="c1"># {"action": "traded", "amount": 42, "item": "shrubs"}</span> </pre></div> </div> <p>This approach has a couple advantages over the custom message approach to structured logging:</p> <ul class="simple"> <li>Developers can log a t-string directly without wrapping it in a custom class.</li> <li>Human-readable and structured output can be sent to separate log streams. This is useful for log aggregation systems that process structured data independently from human-readable data.</li> </ul> <div class="admonition note"> <p class="admonition-title">Note</p> <p>Example code</p> <p>See <a class="reference external" href="https://github.com/davepeck/pep750-examples/blob/main/pep/logging.py">logging.py</a> and <a class="reference external" href="https://github.com/davepeck/pep750-examples/blob/main/pep/test_logging.py">test_logging.py</a>.</p> </div> </section> </section> <section id="example-html-templating"> <h3><a class="toc-backref" href="#example-html-templating" role="doc-backlink">Example: HTML Templating</a></h3> <p>This PEP contains several short HTML templating examples. It turns out that the “hypothetical” <code class="docutils literal notranslate"><span class="pre">html()</span></code> function mentioned in the <a class="reference internal" href="#motivation">Motivation</a> section (and a few other places in this PEP) exists and is available in the <a class="reference external" href="https://github.com/davepeck/pep750-examples/">pep750-examples repository</a>. If you’re thinking about parsing a complex grammar with template strings, we hope you’ll find it useful.</p> </section> </section> <section id="backwards-compatibility"> <h2><a class="toc-backref" href="#backwards-compatibility" role="doc-backlink">Backwards Compatibility</a></h2> <p>Like f-strings, use of template strings will be a syntactic backwards incompatibility with previous versions.</p> </section> <section id="security-implications"> <h2><a class="toc-backref" href="#security-implications" role="doc-backlink">Security Implications</a></h2> <p>The security implications of working with template strings, with respect to interpolations, are as follows:</p> <ol class="arabic simple"> <li>Scope lookup is the same as f-strings (lexical scope). This model has been shown to work well in practice.</li> <li>Code that processes <code class="docutils literal notranslate"><span class="pre">Template</span></code> instances can ensure that any interpolations are processed in a safe fashion, including respecting the context in which they appear.</li> </ol> </section> <section id="how-to-teach-this"> <h2><a class="toc-backref" href="#how-to-teach-this" role="doc-backlink">How To Teach This</a></h2> <p>Template strings have several audiences:</p> <ul class="simple"> <li>Developers using template strings and processing functions</li> <li>Authors of template processing code</li> <li>Framework authors who build interesting machinery with template strings</li> </ul> <p>We hope that teaching developers will be straightforward. At a glance, template strings look just like f-strings. Their syntax is familiar and the scoping rules remain the same.</p> <p>The first thing developers must learn is that template string literals don’t evaluate to strings; instead, they evaluate to a new type, <code class="docutils literal notranslate"><span class="pre">Template</span></code>. This is a simple type intended to be used by template processing code. It’s not until developers call a processing function that they get the result they want: typically, a string, although processing code can of course return any arbitrary type.</p> <p>Developers will also want to understand how template strings relate to other string formatting methods like f-strings and <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#str.format" title="(in Python v3.13)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">str.format()</span></code></a>. They will need to decide when to use each method. If a simple string is all that is needed, and there are no security implications, f-strings are likely the best choice. For most cases where a format string is used, it can be replaced with a function wrapping the creation of a template string. In cases where the format string is obtained from user input, the filesystem, or databases, it is possible to write code to convert it into a <code class="docutils literal notranslate"><span class="pre">Template</span></code> instance if desired.</p> <p>Because developers will learn that t-strings are nearly always used in tandem with processing functions, they don’t necessarily need to understand the details of the <code class="docutils literal notranslate"><span class="pre">Template</span></code> type. As with descriptors and decorators, we expect many more developers will use t-strings than write t-string processing functions.</p> <p>Over time, a small number of more advanced developers <em>will</em> wish to author their own template processing code. Writing processing code often requires thinking in terms of formal grammars. Developers will need to learn how to work with the <code class="docutils literal notranslate"><span class="pre">strings</span></code> and <code class="docutils literal notranslate"><span class="pre">interpolation</span></code> attributes of a <code class="docutils literal notranslate"><span class="pre">Template</span></code> instance and how to process interpolations in a context-sensitive fashion. More sophisticated grammars will likely require parsing to intermediate representations like an AST. Great template processing code will handle format specifiers and conversions when appropriate. Writing production-grade template processing code – for instance, to support HTML templates – can be a large undertaking.</p> <p>We expect that template strings will provide framework authors with a powerful new tool in their toolbox. While the functionality of template strings overlaps with existing tools like template engines, t-strings move that logic into the language itself. Bringing the full power and generality of Python to bear on string processing tasks opens new possibilities for framework authors.</p> </section> <section id="why-another-templating-approach"> <h2><a class="toc-backref" href="#why-another-templating-approach" role="doc-backlink">Why another templating approach?</a></h2> <p>The world of Python already has mature templating languages with wide adoption, such as Jinja. Why build support for creating new templating systems?</p> <p>Projects such as Jinja are still needed in cases where the template is less part of the software by the developers, and more part of customization by designers or even content created by users, for example in a CMS.</p> <p>The trends in frontend development have treated templating as part of the software and written by developers. They want modern language features and a good tooling experience. PEP 750 envisions DSLs where the non-static parts are Python: same scope rules, typing, expression syntax, and the like.</p> </section> <section id="common-patterns-seen-in-processing-templates"> <h2><a class="toc-backref" href="#common-patterns-seen-in-processing-templates" role="doc-backlink">Common Patterns Seen in Processing Templates</a></h2> <section id="structural-pattern-matching"> <h3><a class="toc-backref" href="#structural-pattern-matching" role="doc-backlink">Structural Pattern Matching</a></h3> <p>Iterating over the <code class="docutils literal notranslate"><span class="pre">Template</span></code> with structural pattern matching is the expected best practice for many template function implementations:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span><span class="w"> </span><span class="nn">TBD</span><span class="w"> </span><span class="kn">import</span> <span class="n">Template</span><span class="p">,</span> <span class="n">Interpolation</span> <span class="k">def</span><span class="w"> </span><span class="nf">process</span><span class="p">(</span><span class="n">template</span><span class="p">:</span> <span class="n">Template</span><span class="p">)</span> <span class="o">-></span> <span class="n">Any</span><span class="p">:</span> <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">template</span><span class="p">:</span> <span class="k">match</span> <span class="n">item</span><span class="p">:</span> <span class="k">case</span> <span class="nb">str</span><span class="p">()</span> <span class="k">as</span> <span class="n">s</span><span class="p">:</span> <span class="o">...</span> <span class="c1"># handle each string part</span> <span class="k">case</span> <span class="n">Interpolation</span><span class="p">()</span> <span class="k">as</span> <span class="n">interpolation</span><span class="p">:</span> <span class="o">...</span> <span class="c1"># handle each interpolation</span> </pre></div> </div> <p>Processing code may also commonly sub-match on attributes of the <code class="docutils literal notranslate"><span class="pre">Interpolation</span></code> type:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">match</span> <span class="n">arg</span><span class="p">:</span> <span class="k">case</span> <span class="n">Interpolation</span><span class="p">(</span><span class="nb">int</span><span class="p">()):</span> <span class="o">...</span> <span class="c1"># handle interpolations with integer values</span> <span class="k">case</span> <span class="n">Interpolation</span><span class="p">(</span><span class="n">value</span><span class="o">=</span><span class="nb">str</span><span class="p">()</span> <span class="k">as</span> <span class="n">s</span><span class="p">):</span> <span class="o">...</span> <span class="c1"># handle interpolations with string values</span> <span class="c1"># etc.</span> </pre></div> </div> </section> <section id="memoizing"> <h3><a class="toc-backref" href="#memoizing" role="doc-backlink">Memoizing</a></h3> <p>Template functions can efficiently process both static and dynamic parts of templates. The structure of <code class="docutils literal notranslate"><span class="pre">Template</span></code> objects allows for effective memoization:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">strings</span> <span class="o">=</span> <span class="n">template</span><span class="o">.</span><span class="n">strings</span> <span class="c1"># Static string parts</span> <span class="n">values</span> <span class="o">=</span> <span class="n">template</span><span class="o">.</span><span class="n">values</span> <span class="c1"># Dynamic interpolated values</span> </pre></div> </div> <p>This separation enables caching of processed static parts while dynamic parts can be inserted as needed. Authors of template processing code can use the static <code class="docutils literal notranslate"><span class="pre">strings</span></code> as cache keys, leading to significant performance improvements when similar templates are used repeatedly.</p> </section> <section id="parsing-to-intermediate-representations"> <h3><a class="toc-backref" href="#parsing-to-intermediate-representations" role="doc-backlink">Parsing to Intermediate Representations</a></h3> <p>Code that processes templates can parse the template string into intermediate representations, like an AST. We expect that many template processing libraries will use this approach.</p> <p>For instance, rather than returning a <code class="docutils literal notranslate"><span class="pre">str</span></code>, our theoretical <code class="docutils literal notranslate"><span class="pre">html()</span></code> function (see the <a class="reference internal" href="#motivation">Motivation</a> section) could return an HTML <code class="docutils literal notranslate"><span class="pre">Element</span></code> defined in the same package:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="nd">@dataclass</span><span class="p">(</span><span class="n">frozen</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> <span class="k">class</span><span class="w"> </span><span class="nc">Element</span><span class="p">:</span> <span class="n">tag</span><span class="p">:</span> <span class="nb">str</span> <span class="n">attributes</span><span class="p">:</span> <span class="n">Mapping</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span> <span class="o">|</span> <span class="nb">bool</span><span class="p">]</span> <span class="n">children</span><span class="p">:</span> <span class="n">Sequence</span><span class="p">[</span><span class="nb">str</span> <span class="o">|</span> <span class="n">Element</span><span class="p">]</span> <span class="k">def</span><span class="w"> </span><span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span> <span class="o">...</span> <span class="k">def</span><span class="w"> </span><span class="nf">html</span><span class="p">(</span><span class="n">template</span><span class="p">:</span> <span class="n">Template</span><span class="p">)</span> <span class="o">-></span> <span class="n">Element</span><span class="p">:</span> <span class="o">...</span> </pre></div> </div> <p>Calling <code class="docutils literal notranslate"><span class="pre">str(element)</span></code> would then render the HTML but, in the meantime, the <code class="docutils literal notranslate"><span class="pre">Element</span></code> could be manipulated in a variety of ways.</p> </section> <section id="context-sensitive-processing-of-interpolations"> <h3><a class="toc-backref" href="#context-sensitive-processing-of-interpolations" role="doc-backlink">Context-sensitive Processing of Interpolations</a></h3> <p>Continuing with our hypothetical <code class="docutils literal notranslate"><span class="pre">html()</span></code> function, it could be made context-sensitive. Interpolations could be processed differently depending on where they appear in the template.</p> <p>For example, our <code class="docutils literal notranslate"><span class="pre">html()</span></code> function could support multiple kinds of interpolations:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">attributes</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"id"</span><span class="p">:</span> <span class="s2">"main"</span><span class="p">}</span> <span class="n">attribute_value</span> <span class="o">=</span> <span class="s2">"shrubbery"</span> <span class="n">content</span> <span class="o">=</span> <span class="s2">"hello"</span> <span class="n">template</span> <span class="o">=</span> <span class="n">t</span><span class="s2">"<div </span><span class="si">{attributes}</span><span class="s2"> data-value=</span><span class="si">{attribute_value}</span><span class="s2">></span><span class="si">{content}</span><span class="s2"></div>"</span> <span class="n">element</span> <span class="o">=</span> <span class="n">html</span><span class="p">(</span><span class="n">template</span><span class="p">)</span> <span class="k">assert</span> <span class="nb">str</span><span class="p">(</span><span class="n">element</span><span class="p">)</span> <span class="o">==</span> <span class="s1">'<div id="main" data-value="shrubbery">hello</div>'</span> </pre></div> </div> <p>Because the <code class="docutils literal notranslate"><span class="pre">{attributes}</span></code> interpolation occurs in the context of an HTML tag, and because there is no corresponding attribute name, it is treated as a dictionary of attributes. The <code class="docutils literal notranslate"><span class="pre">{attribute_value}</span></code> interpolation is treated as a simple string value and is quoted before inclusion in the final string. The <code class="docutils literal notranslate"><span class="pre">{content}</span></code> interpolation is treated as potentially unsafe content and is escaped before inclusion in the final string.</p> </section> <section id="nested-template-strings"> <h3><a class="toc-backref" href="#nested-template-strings" role="doc-backlink">Nested Template Strings</a></h3> <p>Going a step further with our <code class="docutils literal notranslate"><span class="pre">html()</span></code> function, we could support nested template strings. This would allow for more complex HTML structures to be built up from simpler templates:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">name</span> <span class="o">=</span> <span class="s2">"World"</span> <span class="n">content</span> <span class="o">=</span> <span class="n">html</span><span class="p">(</span><span class="n">t</span><span class="s2">"<p>Hello </span><span class="si">{name}</span><span class="s2"></p>"</span><span class="p">)</span> <span class="n">template</span> <span class="o">=</span> <span class="n">t</span><span class="s2">"<div></span><span class="si">{content}</span><span class="s2"></div>"</span> <span class="n">element</span> <span class="o">=</span> <span class="n">html</span><span class="p">(</span><span class="n">template</span><span class="p">)</span> <span class="k">assert</span> <span class="nb">str</span><span class="p">(</span><span class="n">element</span><span class="p">)</span> <span class="o">==</span> <span class="s1">'<div><p>Hello World</p></div>'</span> </pre></div> </div> <p>Because the <code class="docutils literal notranslate"><span class="pre">{content}</span></code> interpolation is an <code class="docutils literal notranslate"><span class="pre">Element</span></code> instance, it does not need to be escaped before inclusion in the final string.</p> <p>One could imagine a nice simplification: if the <code class="docutils literal notranslate"><span class="pre">html()</span></code> function is passed a <code class="docutils literal notranslate"><span class="pre">Template</span></code> instance, it could automatically convert it to an <code class="docutils literal notranslate"><span class="pre">Element</span></code> by recursively calling itself on the nested template.</p> <p>We expect that nesting and composition of templates will be a common pattern in template processing code and, where appropriate, used in preference to simple string concatenation.</p> </section> <section id="approaches-to-lazy-evaluation"> <h3><a class="toc-backref" href="#approaches-to-lazy-evaluation" role="doc-backlink">Approaches to Lazy Evaluation</a></h3> <p>Like f-strings, interpolations in t-string literals are eagerly evaluated. However, there are cases where lazy evaluation may be desirable.</p> <p>If a single interpolation is expensive to evaluate, it can be explicitly wrapped in a <code class="docutils literal notranslate"><span class="pre">lambda</span></code> in the template string literal:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">name</span> <span class="o">=</span> <span class="s2">"World"</span> <span class="n">template</span> <span class="o">=</span> <span class="n">t</span><span class="s2">"Hello {(lambda: name)}"</span> <span class="k">assert</span> <span class="nb">callable</span><span class="p">(</span><span class="n">template</span><span class="o">.</span><span class="n">interpolations</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">value</span><span class="p">)</span> <span class="k">assert</span> <span class="n">template</span><span class="o">.</span><span class="n">interpolations</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">value</span><span class="p">()</span> <span class="o">==</span> <span class="s2">"World"</span> </pre></div> </div> <p>This assumes, of course, that template processing code anticipates and handles callable interpolation values. (One could imagine also supporting iterators, awaitables, etc.) This is not a requirement of the PEP, but it is a common pattern in template processing code.</p> <p>In general, we hope that the community will develop best practices for lazy evaluation of interpolations in template strings and that, when it makes sense, common libraries will provide support for callable or awaitable values in their template processing code.</p> </section> <section id="approaches-to-asynchronous-evaluation"> <h3><a class="toc-backref" href="#approaches-to-asynchronous-evaluation" role="doc-backlink">Approaches to Asynchronous Evaluation</a></h3> <p>Closely related to lazy evaluation is asynchronous evaluation.</p> <p>As with f-strings, the <code class="docutils literal notranslate"><span class="pre">await</span></code> keyword is allowed in interpolations:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">example</span><span class="p">():</span> <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">get_name</span><span class="p">()</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span> <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="k">return</span> <span class="s2">"Sleepy"</span> <span class="n">template</span> <span class="o">=</span> <span class="n">t</span><span class="s2">"Hello {await get_name()}"</span> <span class="c1"># Use the f() function from the f-string example, above</span> <span class="k">assert</span> <span class="n">f</span><span class="p">(</span><span class="n">template</span><span class="p">)</span> <span class="o">==</span> <span class="s2">"Hello Sleepy"</span> </pre></div> </div> <p>More sophisticated template processing code can take advantage of this to perform asynchronous operations in interpolations. For example, a “smart” processing function could anticipate that an interpolation is an awaitable and await it before processing the template string:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">example</span><span class="p">():</span> <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">get_name</span><span class="p">()</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span> <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="k">return</span> <span class="s2">"Sleepy"</span> <span class="n">template</span> <span class="o">=</span> <span class="n">t</span><span class="s2">"Hello </span><span class="si">{get_name}</span><span class="s2">"</span> <span class="k">assert</span> <span class="k">await</span> <span class="n">async_f</span><span class="p">(</span><span class="n">template</span><span class="p">)</span> <span class="o">==</span> <span class="s2">"Hello Sleepy"</span> </pre></div> </div> <p>This assumes that the template processing code in <code class="docutils literal notranslate"><span class="pre">async_f()</span></code> is asynchronous and is able to <code class="docutils literal notranslate"><span class="pre">await</span></code> an interpolation’s value.</p> <div class="admonition note"> <p class="admonition-title">Note</p> <p>Example code</p> <p>See <a class="reference external" href="https://github.com/davepeck/pep750-examples/blob/main/pep/afstring.py">afstring.py</a> and <a class="reference external" href="https://github.com/davepeck/pep750-examples/blob/main/pep/test_afstring.py">test_afstring.py</a>.</p> </div> </section> <section id="approaches-to-template-reuse"> <h3><a class="toc-backref" href="#approaches-to-template-reuse" role="doc-backlink">Approaches to Template Reuse</a></h3> <p>If developers wish to reuse template strings multiple times with different values, they can write a function to return a <code class="docutils literal notranslate"><span class="pre">Template</span></code> instance:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">reusable</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">question</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="n">Template</span><span class="p">:</span> <span class="k">return</span> <span class="n">t</span><span class="s2">"Hello </span><span class="si">{name}</span><span class="s2">, </span><span class="si">{question}</span><span class="s2">?"</span> <span class="n">template</span> <span class="o">=</span> <span class="n">reusable</span><span class="p">(</span><span class="s2">"friend"</span><span class="p">,</span> <span class="s2">"how are you"</span><span class="p">)</span> <span class="n">template</span> <span class="o">=</span> <span class="n">reusable</span><span class="p">(</span><span class="s2">"King Arthur"</span><span class="p">,</span> <span class="s2">"what is your quest"</span><span class="p">)</span> </pre></div> </div> <p>This is, of course, no different from how f-strings can be reused.</p> </section> <section id="relation-to-format-strings"> <h3><a class="toc-backref" href="#relation-to-format-strings" role="doc-backlink">Relation to Format Strings</a></h3> <p>The venerable <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#str.format" title="(in Python v3.13)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">str.format()</span></code></a> method accepts format strings that can later be used to format values:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">alas_fmt</span> <span class="o">=</span> <span class="s2">"We're all out of </span><span class="si">{cheese}</span><span class="s2">."</span> <span class="k">assert</span> <span class="n">alas_fmt</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">cheese</span><span class="o">=</span><span class="s2">"Red Leicester"</span><span class="p">)</span> <span class="o">==</span> <span class="s2">"We're all out of Red Leicester."</span> </pre></div> </div> <p>If one squints, one can think of format strings as a kind of function definition. The <em>call</em> to <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#str.format" title="(in Python v3.13)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">str.format()</span></code></a> can be seen as a kind of function call. The t-string equivalent is to simply define a standard Python function that returns a <code class="docutils literal notranslate"><span class="pre">Template</span></code> instance:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">make_template</span><span class="p">(</span><span class="o">*</span><span class="p">,</span> <span class="n">cheese</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="n">Template</span><span class="p">:</span> <span class="k">return</span> <span class="n">t</span><span class="s2">"We're all out of </span><span class="si">{cheese}</span><span class="s2">."</span> <span class="n">template</span> <span class="o">=</span> <span class="n">make_template</span><span class="p">(</span><span class="n">cheese</span><span class="o">=</span><span class="s2">"Red Leicester"</span><span class="p">)</span> <span class="c1"># Using the f() function from the f-string example, above</span> <span class="k">assert</span> <span class="n">f</span><span class="p">(</span><span class="n">template</span><span class="p">)</span> <span class="o">==</span> <span class="s2">"We're all out of Red Leicester."</span> </pre></div> </div> <p>The <code class="docutils literal notranslate"><span class="pre">make_template()</span></code> function itself can be thought of as analogous to the format string. The call to <code class="docutils literal notranslate"><span class="pre">make_template()</span></code> is analogous to the call to <a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#str.format" title="(in Python v3.13)"><code class="xref py py-meth docutils literal notranslate"><span class="pre">str.format()</span></code></a>.</p> <p>Of course, it is common to load format strings from external sources like a filesystem or database. Thankfully, because <code class="docutils literal notranslate"><span class="pre">Template</span></code> and <code class="docutils literal notranslate"><span class="pre">Interpolation</span></code> are simple Python types, it is possible to write a function that takes an old-style format string and returns an equivalent <code class="docutils literal notranslate"><span class="pre">Template</span></code> instance:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">from_format</span><span class="p">(</span><span class="n">fmt</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="o">/</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">:</span> <span class="nb">object</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">:</span> <span class="nb">object</span><span class="p">)</span> <span class="o">-></span> <span class="n">Template</span><span class="p">:</span> <span class="w"> </span><span class="sd">"""Parse `fmt` and return a `Template` instance."""</span> <span class="o">...</span> <span class="c1"># Load this from a file, database, etc.</span> <span class="n">fmt</span> <span class="o">=</span> <span class="s2">"We're all out of </span><span class="si">{cheese}</span><span class="s2">."</span> <span class="n">template</span> <span class="o">=</span> <span class="n">from_format</span><span class="p">(</span><span class="n">fmt</span><span class="p">,</span> <span class="n">cheese</span><span class="o">=</span><span class="s2">"Red Leicester"</span><span class="p">)</span> <span class="c1"># Using the f() function from the f-string example, above</span> <span class="k">assert</span> <span class="n">f</span><span class="p">(</span><span class="n">template</span><span class="p">)</span> <span class="o">==</span> <span class="s2">"We're all out of Red Leicester."</span> </pre></div> </div> <p>This is a powerful pattern that allows developers to use template strings in places where they might have previously used format strings. A full implementation of <code class="docutils literal notranslate"><span class="pre">from_format()</span></code> is available in the examples repository, which supports the full grammar of format strings.</p> <div class="admonition note"> <p class="admonition-title">Note</p> <p>Example code</p> <p>See <a class="reference external" href="https://github.com/davepeck/pep750-examples/blob/main/pep/format.py">format.py</a> and <a class="reference external" href="https://github.com/davepeck/pep750-examples/blob/main/pep/test_format.py">test_format.py</a>.</p> </div> </section> </section> <section id="reference-implementation"> <h2><a class="toc-backref" href="#reference-implementation" role="doc-backlink">Reference Implementation</a></h2> <p>A CPython implementation of PEP 750 is <a class="reference external" href="https://github.com/lysnikolaou/cpython/tree/tstrings">available</a>.</p> <p>There is also a public repository of <a class="reference external" href="https://github.com/davepeck/pep750-examples">examples and tests</a> built around the reference implementation. If you’re interested in playing with template strings, this repository is a great place to start.</p> </section> <section id="rejected-ideas"> <h2><a class="toc-backref" href="#rejected-ideas" role="doc-backlink">Rejected Ideas</a></h2> <p>This PEP has been through several significant revisions. In addition, quite a few interesting ideas were considered both in revisions of <a class="pep reference internal" href="../pep-0501/" title="PEP 501 – General purpose template literal strings">PEP 501</a> and in the <a class="reference external" href="https://discuss.python.org/t/pep-750-tag-strings-for-writing-domain-specific-languages/60408/196">Discourse discussion</a>.</p> <p>We attempt to document the most significant ideas that were considered and rejected.</p> <section id="arbitrary-string-literal-prefixes"> <h3><a class="toc-backref" href="#arbitrary-string-literal-prefixes" role="doc-backlink">Arbitrary String Literal Prefixes</a></h3> <p>Inspired by <a class="reference external" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates">JavaScript tagged template literals</a>, an earlier version of this PEP allowed for arbitrary “tag” prefixes in front of literal strings:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">my_tag</span><span class="s1">'Hello </span><span class="si">{name}</span><span class="s1">'</span> </pre></div> </div> <p>The prefix was a special callable called a “tag function”. Tag functions received the parts of the template string in an argument list. They could then process the string and return an arbitrary value:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">my_tag</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="n">Interpolation</span><span class="p">)</span> <span class="o">-></span> <span class="n">Any</span><span class="p">:</span> <span class="o">...</span> </pre></div> </div> <p>This approach was rejected for several reasons:</p> <ul class="simple"> <li>It was deemed too complex to build in full generality. JavaScript allows for arbitrary expressions to precede a template string, which is a significant challenge to implement in Python.</li> <li>It precluded future introduction of new string prefixes.</li> <li>It seemed to needlessly pollute the namespace.</li> </ul> <p>Use of a single <code class="docutils literal notranslate"><span class="pre">t</span></code> prefix was chosen as a simpler, more Pythonic approach and more in keeping with template strings’ role as a generalization of f-strings.</p> </section> <section id="delayed-evaluation-of-interpolations"> <h3><a class="toc-backref" href="#delayed-evaluation-of-interpolations" role="doc-backlink">Delayed Evaluation of Interpolations</a></h3> <p>An early version of this PEP proposed that interpolations should be lazily evaluated. All interpolations were “wrapped” in implicit lambdas. Instead of having an eagerly evaluated <code class="docutils literal notranslate"><span class="pre">value</span></code> attribute, interpolations had a <code class="docutils literal notranslate"><span class="pre">getvalue()</span></code> method that would resolve the value of the interpolation:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">Interpolation</span><span class="p">:</span> <span class="o">...</span> <span class="n">_value</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[[],</span> <span class="nb">object</span><span class="p">]</span> <span class="k">def</span><span class="w"> </span><span class="nf">getvalue</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="nb">object</span><span class="p">:</span> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_value</span><span class="p">()</span> </pre></div> </div> <p>This was rejected for several reasons:</p> <ul class="simple"> <li>The overwhelming majority of use cases for template strings naturally call for immediate evaluation.</li> <li>Delayed evaluation would be a significant departure from the behavior of f-strings.</li> <li>Implicit lambda wrapping leads to difficulties with type hints and static analysis.</li> </ul> <p>Most importantly, there are viable (if imperfect) alternatives to implicit lambda wrapping in many cases where lazy evaluation is desired. See the section on <a class="reference internal" href="#approaches-to-lazy-evaluation">Approaches to Lazy Evaluation</a>, above, for more information.</p> <p>While delayed evaluation was rejected for <em>this</em> PEP, we hope that the community continues to explore the idea.</p> </section> <section id="making-template-and-interpolation-into-protocols"> <h3><a class="toc-backref" href="#making-template-and-interpolation-into-protocols" role="doc-backlink">Making <code class="docutils literal notranslate"><span class="pre">Template</span></code> and <code class="docutils literal notranslate"><span class="pre">Interpolation</span></code> Into Protocols</a></h3> <p>An early version of this PEP proposed that the <code class="docutils literal notranslate"><span class="pre">Template</span></code> and <code class="docutils literal notranslate"><span class="pre">Interpolation</span></code> types be runtime checkable protocols rather than classes.</p> <p>In the end, we felt that using classes was more straightforward.</p> </section> <section id="overridden-eq-and-hash-for-template-and-interpolation"> <h3><a class="toc-backref" href="#overridden-eq-and-hash-for-template-and-interpolation" role="doc-backlink">Overridden <code class="docutils literal notranslate"><span class="pre">__eq__</span></code> and <code class="docutils literal notranslate"><span class="pre">__hash__</span></code> for <code class="docutils literal notranslate"><span class="pre">Template</span></code> and <code class="docutils literal notranslate"><span class="pre">Interpolation</span></code></a></h3> <p>Earlier versions of this PEP proposed that the <code class="docutils literal notranslate"><span class="pre">Template</span></code> and <code class="docutils literal notranslate"><span class="pre">Interpolation</span></code> types should have their own implementations of <code class="docutils literal notranslate"><span class="pre">__eq__</span></code> and <code class="docutils literal notranslate"><span class="pre">__hash__</span></code>.</p> <p><code class="docutils literal notranslate"><span class="pre">Templates</span></code> were considered equal if their <code class="docutils literal notranslate"><span class="pre">strings</span></code> and <code class="docutils literal notranslate"><span class="pre">interpolations</span></code> were equal; <code class="docutils literal notranslate"><span class="pre">Interpolations</span></code> were considered equal if their <code class="docutils literal notranslate"><span class="pre">value</span></code>, <code class="docutils literal notranslate"><span class="pre">expr</span></code>, <code class="docutils literal notranslate"><span class="pre">conv</span></code>, and <code class="docutils literal notranslate"><span class="pre">format_spec</span></code> were equal. Interpolation hashing was similar to tuple hashing: an <code class="docutils literal notranslate"><span class="pre">Interpolation</span></code> was hashable if and only if its <code class="docutils literal notranslate"><span class="pre">value</span></code> was hashable.</p> <p>This was rejected because <code class="docutils literal notranslate"><span class="pre">Template.__hash__</span></code> so defined was not useful as a cache key in template processing code; we were concerned that it would be confusing to developers.</p> <p>By dropping these implementations of <code class="docutils literal notranslate"><span class="pre">__eq__</span></code> and <code class="docutils literal notranslate"><span class="pre">__hash__</span></code>, we lose the ability to write asserts such as:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">name</span> <span class="o">=</span> <span class="s2">"World"</span> <span class="k">assert</span> <span class="n">t</span><span class="s2">"Hello "</span> <span class="o">+</span> <span class="n">t</span><span class="s2">"</span><span class="si">{name}</span><span class="s2">"</span> <span class="o">==</span> <span class="n">t</span><span class="s2">"Hello </span><span class="si">{name}</span><span class="s2">"</span> </pre></div> </div> <p>Because <code class="docutils literal notranslate"><span class="pre">Template</span></code> instances are intended to be quickly processed by further code, we felt that the utility of these asserts was limited.</p> </section> <section id="an-additional-decoded-type"> <h3><a class="toc-backref" href="#an-additional-decoded-type" role="doc-backlink">An Additional <code class="docutils literal notranslate"><span class="pre">Decoded</span></code> Type</a></h3> <p>An early version of this PEP proposed an additional type, <code class="docutils literal notranslate"><span class="pre">Decoded</span></code>, to represent the “static string” parts of a template string. This type derived from <code class="docutils literal notranslate"><span class="pre">str</span></code> and had a single extra <code class="docutils literal notranslate"><span class="pre">raw</span></code> attribute that provided the original text of the string. We rejected this in favor of the simpler approach of using plain <code class="docutils literal notranslate"><span class="pre">str</span></code> and allowing combination of <code class="docutils literal notranslate"><span class="pre">r</span></code> and <code class="docutils literal notranslate"><span class="pre">t</span></code> prefixes.</p> </section> <section id="the-final-home-for-template-and-interpolation"> <h3><a class="toc-backref" href="#the-final-home-for-template-and-interpolation" role="doc-backlink">The Final Home for <code class="docutils literal notranslate"><span class="pre">Template</span></code> and <code class="docutils literal notranslate"><span class="pre">Interpolation</span></code></a></h3> <p>Previous versions of this PEP proposed placing the <code class="docutils literal notranslate"><span class="pre">Template</span></code> and <code class="docutils literal notranslate"><span class="pre">Interpolation</span></code> types in: <code class="docutils literal notranslate"><span class="pre">types</span></code>, <code class="docutils literal notranslate"><span class="pre">collections</span></code>, <code class="docutils literal notranslate"><span class="pre">collections.abc</span></code>, and even in a new top-level module, <code class="docutils literal notranslate"><span class="pre">templatelib</span></code>. As of this writing, no core team consensus has emerged on the final location for these types. The current PEP leaves this open for a final decision.</p> <p>One argument in favor of a new top-level <code class="docutils literal notranslate"><span class="pre">templatelib</span></code> module is that it would allow for future addition of related methods (like <code class="docutils literal notranslate"><span class="pre">convert()</span></code>) and for potential future template processing code to be added to submodules (<code class="docutils literal notranslate"><span class="pre">templatelib.shell</span></code>, etc.).</p> </section> <section id="enable-full-reconstruction-of-original-template-literal"> <h3><a class="toc-backref" href="#enable-full-reconstruction-of-original-template-literal" role="doc-backlink">Enable Full Reconstruction of Original Template Literal</a></h3> <p>Earlier versions of this PEP attempted to make it possible to fully reconstruct the text of the original template string from a <code class="docutils literal notranslate"><span class="pre">Template</span></code> instance. This was rejected as being overly complex.</p> <p>There are several limitations with respect to round-tripping to the original source text:</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">Interpolation.format_spec</span></code> defaults to <code class="docutils literal notranslate"><span class="pre">""</span></code> if not provided. It is therefore impossible to distinguish <code class="docutils literal notranslate"><span class="pre">t"{expr}"</span></code> from <code class="docutils literal notranslate"><span class="pre">t"{expr:}"</span></code>.</li> <li>The debug specifier, <code class="docutils literal notranslate"><span class="pre">=</span></code>, is treated as a special case. It is therefore not possible to distinguish <code class="docutils literal notranslate"><span class="pre">t"{expr=}"</span></code> from <code class="docutils literal notranslate"><span class="pre">t"expr={expr}"</span></code>.</li> <li>Finally, format specifiers in f-strings allow arbitrary nesting. In this PEP and in the reference implementation, the specifier is eagerly evaluated to set the <code class="docutils literal notranslate"><span class="pre">format_spec</span></code> in the <code class="docutils literal notranslate"><span class="pre">Interpolation</span></code>, thereby losing the original expressions. For example:</li> </ul> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">value</span> <span class="o">=</span> <span class="mi">42</span> <span class="n">precision</span> <span class="o">=</span> <span class="mi">2</span> <span class="n">template</span> <span class="o">=</span> <span class="n">t</span><span class="s2">"Value: {value:.</span><span class="si">{precision}</span><span class="s2">f}"</span> <span class="k">assert</span> <span class="n">template</span><span class="o">.</span><span class="n">interpolations</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">format_spec</span> <span class="o">==</span> <span class="s2">".2f"</span> </pre></div> </div> <p>We do not anticipate that these limitations will be a significant issue in practice. Developers who need to obtain the original template string literal can always use <code class="docutils literal notranslate"><span class="pre">inspect.getsource()</span></code> or similar tools.</p> </section> <section id="disallowing-string-concatenation"> <h3><a class="toc-backref" href="#disallowing-string-concatenation" role="doc-backlink">Disallowing String Concatenation</a></h3> <p>Earlier versions of this PEP proposed that template strings should not support concatenation. This was rejected in favor of allowing concatenation.</p> <p>There are reasonable arguments in favor of rejecting one or all forms of concatenation: namely, that it cuts off a class of potential bugs, particularly when one takes the view that template strings will often contain complex grammars for which concatenation doesn’t always have the same meaning (or any meaning).</p> <p>Moreover, the earliest versions of this PEP proposed a syntax closer to JavaScript’s tagged template literals, where an arbitrary callable could be used as a prefix to a string literal. There was no guarantee that the callable would return a type that supported concatenation.</p> <p>In the end, we decided that the surprise to developers of a new string type <em>not</em> supporting concatenation was likely to be greater than the theoretical harm caused by supporting it. (Developers concatenate f-strings all the time, after all, and while we are sure there are cases where this introduces bugs, it’s not clear that those bugs outweigh the benefits of supporting concatenation.)</p> <p>While concatenation is supported, we expect that code that uses template strings will more commonly build up larger templates through nesting and composition rather than concatenation.</p> </section> <section id="arbitrary-conversion-values"> <h3><a class="toc-backref" href="#arbitrary-conversion-values" role="doc-backlink">Arbitrary Conversion Values</a></h3> <p>Python allows only <code class="docutils literal notranslate"><span class="pre">r</span></code>, <code class="docutils literal notranslate"><span class="pre">s</span></code>, or <code class="docutils literal notranslate"><span class="pre">a</span></code> as possible conversion type values. Trying to assign a different value results in <code class="docutils literal notranslate"><span class="pre">SyntaxError</span></code>.</p> <p>In theory, template functions could choose to handle other conversion types. But this PEP adheres closely to <a class="pep reference internal" href="../pep-0701/" title="PEP 701 – Syntactic formalization of f-strings">PEP 701</a>. Any changes to allowed values should be in a separate PEP.</p> </section> <section id="removing-conv-from-interpolation"> <h3><a class="toc-backref" href="#removing-conv-from-interpolation" role="doc-backlink">Removing <code class="docutils literal notranslate"><span class="pre">conv</span></code> From <code class="docutils literal notranslate"><span class="pre">Interpolation</span></code></a></h3> <p>During the authoring of this PEP, we considered removing the <code class="docutils literal notranslate"><span class="pre">conv</span></code> attribute from <code class="docutils literal notranslate"><span class="pre">Interpolation</span></code> and specifying that the conversion should be performed eagerly, before <code class="docutils literal notranslate"><span class="pre">Interpolation.value</span></code> is set.</p> <p>This was done to simplify the work of writing template processing code. The <code class="docutils literal notranslate"><span class="pre">conv</span></code> attribute is of limited extensibility (it is typed as <code class="docutils literal notranslate"><span class="pre">Literal["r",</span> <span class="pre">"s",</span> <span class="pre">"a"]</span> <span class="pre">|</span> <span class="pre">None</span></code>). It is not clear that it adds significant value or flexibility to template strings that couldn’t better be achieved with custom format specifiers. Unlike with format specifiers, there is no equivalent to Python’s <a class="reference external" href="https://docs.python.org/3/library/functions.html#format" title="(in Python v3.13)"><code class="docutils literal notranslate"><span class="pre">format()</span></code></a> built-in. (Instead, we include an sample implementation of <code class="docutils literal notranslate"><span class="pre">convert()</span></code> in the <a class="reference internal" href="#examples">Examples</a> section.)</p> <p>Ultimately we decided to keep the <code class="docutils literal notranslate"><span class="pre">conv</span></code> attribute in the <code class="docutils literal notranslate"><span class="pre">Interpolation</span></code> type to maintain compatibility with f-strings and to allow for future extensibility.</p> </section> <section id="alternate-interpolation-symbols"> <h3><a class="toc-backref" href="#alternate-interpolation-symbols" role="doc-backlink">Alternate Interpolation Symbols</a></h3> <p>In the early stages of this PEP, we considered allowing alternate symbols for interpolations in template strings. For example, we considered allowing <code class="docutils literal notranslate"><span class="pre">${name}</span></code> as an alternative to <code class="docutils literal notranslate"><span class="pre">{name}</span></code> with the idea that it might be useful for i18n or other purposes. See the <a class="reference external" href="https://discuss.python.org/t/pep-750-tag-strings-for-writing-domain-specific-languages/60408/122">Discourse thread</a> for more information.</p> <p>This was rejected in favor of keeping t-string syntax as close to f-string syntax as possible.</p> </section> <section id="alternate-layouts-for-template"> <h3><a class="toc-backref" href="#alternate-layouts-for-template" role="doc-backlink">Alternate Layouts for <code class="docutils literal notranslate"><span class="pre">Template</span></code></a></h3> <p>During the development of this PEP, we considered several alternate layouts for the <code class="docutils literal notranslate"><span class="pre">Template</span></code> type. Many focused on a single <code class="docutils literal notranslate"><span class="pre">args</span></code> tuple that contained both strings and interpolations. Variants included:</p> <ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">args</span></code> was a <code class="docutils literal notranslate"><span class="pre">tuple[str</span> <span class="pre">|</span> <span class="pre">Interpolation,</span> <span class="pre">...]`</span></code> with the promise that its first and last items were strings and that strings and interpolations always alternated. This implied that <code class="docutils literal notranslate"><span class="pre">args</span></code> was always non-empty and that empty strings would be inserted between neighboring interpolations. This was rejected because alternation could not be captured by the type system and was not a guarantee we wished to make.</li> <li><code class="docutils literal notranslate"><span class="pre">args</span></code> remained a <code class="docutils literal notranslate"><span class="pre">tuple[str</span> <span class="pre">|</span> <span class="pre">Interpolation,</span> <span class="pre">...]</span></code> but did not support interleaving. As a result, empty strings were not added to the sequence. It was no longer possible to obtain static strings with <code class="docutils literal notranslate"><span class="pre">args[::2]</span></code>; instead, instance checks or structural pattern matching had to be used to distinguish between strings and interpolations. This approach was rejected as offering less future opportunity for performance optimization.</li> <li><code class="docutils literal notranslate"><span class="pre">args</span></code> was typed as a <code class="docutils literal notranslate"><span class="pre">Sequence[tuple[str,</span> <span class="pre">Interpolation</span> <span class="pre">|</span> <span class="pre">None]]</span></code>. Each static string was paired with is neighboring interpolation. The final string part had no corresponding interpolation. This was rejected as being overly complex.</li> </ul> </section> <section id="mechanism-to-describe-the-kind-of-template"> <h3><a class="toc-backref" href="#mechanism-to-describe-the-kind-of-template" role="doc-backlink">Mechanism to Describe the “Kind” of Template</a></h3> <p>If t-strings prove popular, it may be useful to have a way to describe the “kind” of content found in a template string: “sql”, “html”, “css”, etc. This could enable powerful new features in tools such as linters, formatters, type checkers, and IDEs. (Imagine, for example, <code class="docutils literal notranslate"><span class="pre">black</span></code> formatting HTML in t-strings, or <code class="docutils literal notranslate"><span class="pre">mypy</span></code> checking whether a given attribute is valid for an HTML tag.) While exciting, this PEP does not propose any specific mechanism. It is our hope that, over time, the community will develop conventions for this purpose.</p> </section> <section id="binary-template-strings"> <h3><a class="toc-backref" href="#binary-template-strings" role="doc-backlink">Binary Template Strings</a></h3> <p>The combination of t-strings and bytes (<code class="docutils literal notranslate"><span class="pre">tb</span></code>) is considered out of scope for this PEP. However, unlike f-strings, there is no fundamental reason why t-strings and bytes cannot be combined. Support could be considered in a future PEP.</p> </section> </section> <section id="acknowledgements"> <h2><a class="toc-backref" href="#acknowledgements" role="doc-backlink">Acknowledgements</a></h2> <p>Thanks to Ryan Morshead for contributions during development of the ideas leading to template strings. Special mention also to Dropbox’s <a class="reference external" href="https://github.com/dropbox/pyxl">pyxl</a> for tackling similar ideas years ago. Andrea Giammarchi provided thoughtful feedback on the early drafts of this PEP. Finally, thanks to Joachim Viide for his pioneering work on the <a class="reference external" href="https://github.com/jviide/tagged">tagged library</a>. Tagged was not just the precursor to template strings, but the place where the whole effort started via a GitHub issue comment!</p> </section> <section id="copyright"> <h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2> <p>This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive.</p> </section> </section> <hr class="docutils" /> <p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0750.rst">https://github.com/python/peps/blob/main/peps/pep-0750.rst</a></p> <p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0750.rst">2025-02-01 07:28:42 GMT</a></p> </article> <nav id="pep-sidebar"> <h2>Contents</h2> <ul> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#relationship-with-other-peps">Relationship With Other PEPs</a></li> <li><a class="reference internal" href="#motivation">Motivation</a></li> <li><a class="reference internal" href="#specification">Specification</a><ul> <li><a class="reference internal" href="#template-string-literals">Template String Literals</a></li> <li><a class="reference internal" href="#the-template-type">The <code class="docutils literal notranslate"><span class="pre">Template</span></code> Type</a></li> <li><a class="reference internal" href="#the-interpolation-type">The <code class="docutils literal notranslate"><span class="pre">Interpolation</span></code> Type</a></li> <li><a class="reference internal" href="#convenience-accessors-in-template">Convenience Accessors in <code class="docutils literal notranslate"><span class="pre">Template</span></code></a></li> <li><a class="reference internal" href="#processing-template-strings">Processing Template Strings</a></li> <li><a class="reference internal" href="#template-string-concatenation">Template String Concatenation</a></li> <li><a class="reference internal" href="#template-and-interpolation-equality">Template and Interpolation Equality</a></li> <li><a class="reference internal" href="#no-support-for-ordering">No Support for Ordering</a></li> <li><a class="reference internal" href="#support-for-the-debug-specifier">Support for the debug specifier (<code class="docutils literal notranslate"><span class="pre">=</span></code>)</a></li> <li><a class="reference internal" href="#raw-template-strings">Raw Template Strings</a></li> <li><a class="reference internal" href="#interpolation-expression-evaluation">Interpolation Expression Evaluation</a></li> <li><a class="reference internal" href="#exceptions">Exceptions</a></li> <li><a class="reference internal" href="#no-template-str-implementation">No <code class="docutils literal notranslate"><span class="pre">Template.__str__()</span></code> Implementation</a></li> </ul> </li> <li><a class="reference internal" href="#examples">Examples</a><ul> <li><a class="reference internal" href="#example-implementing-f-strings-with-t-strings">Example: Implementing f-strings with t-strings</a></li> <li><a class="reference internal" href="#example-structured-logging">Example: Structured Logging</a><ul> <li><a class="reference internal" href="#approach-1-custom-log-messages">Approach 1: Custom Log Messages</a></li> <li><a class="reference internal" href="#approach-2-custom-formatters">Approach 2: Custom Formatters</a></li> </ul> </li> <li><a class="reference internal" href="#example-html-templating">Example: HTML Templating</a></li> </ul> </li> <li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a></li> <li><a class="reference internal" href="#security-implications">Security Implications</a></li> <li><a class="reference internal" href="#how-to-teach-this">How To Teach This</a></li> <li><a class="reference internal" href="#why-another-templating-approach">Why another templating approach?</a></li> <li><a class="reference internal" href="#common-patterns-seen-in-processing-templates">Common Patterns Seen in Processing Templates</a><ul> <li><a class="reference internal" href="#structural-pattern-matching">Structural Pattern Matching</a></li> <li><a class="reference internal" href="#memoizing">Memoizing</a></li> <li><a class="reference internal" href="#parsing-to-intermediate-representations">Parsing to Intermediate Representations</a></li> <li><a class="reference internal" href="#context-sensitive-processing-of-interpolations">Context-sensitive Processing of Interpolations</a></li> <li><a class="reference internal" href="#nested-template-strings">Nested Template Strings</a></li> <li><a class="reference internal" href="#approaches-to-lazy-evaluation">Approaches to Lazy Evaluation</a></li> <li><a class="reference internal" href="#approaches-to-asynchronous-evaluation">Approaches to Asynchronous Evaluation</a></li> <li><a class="reference internal" href="#approaches-to-template-reuse">Approaches to Template Reuse</a></li> <li><a class="reference internal" href="#relation-to-format-strings">Relation to Format Strings</a></li> </ul> </li> <li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li> <li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul> <li><a class="reference internal" href="#arbitrary-string-literal-prefixes">Arbitrary String Literal Prefixes</a></li> <li><a class="reference internal" href="#delayed-evaluation-of-interpolations">Delayed Evaluation of Interpolations</a></li> <li><a class="reference internal" href="#making-template-and-interpolation-into-protocols">Making <code class="docutils literal notranslate"><span class="pre">Template</span></code> and <code class="docutils literal notranslate"><span class="pre">Interpolation</span></code> Into Protocols</a></li> <li><a class="reference internal" href="#overridden-eq-and-hash-for-template-and-interpolation">Overridden <code class="docutils literal notranslate"><span class="pre">__eq__</span></code> and <code class="docutils literal notranslate"><span class="pre">__hash__</span></code> for <code class="docutils literal notranslate"><span class="pre">Template</span></code> and <code class="docutils literal notranslate"><span class="pre">Interpolation</span></code></a></li> <li><a class="reference internal" href="#an-additional-decoded-type">An Additional <code class="docutils literal notranslate"><span class="pre">Decoded</span></code> Type</a></li> <li><a class="reference internal" href="#the-final-home-for-template-and-interpolation">The Final Home for <code class="docutils literal notranslate"><span class="pre">Template</span></code> and <code class="docutils literal notranslate"><span class="pre">Interpolation</span></code></a></li> <li><a class="reference internal" href="#enable-full-reconstruction-of-original-template-literal">Enable Full Reconstruction of Original Template Literal</a></li> <li><a class="reference internal" href="#disallowing-string-concatenation">Disallowing String Concatenation</a></li> <li><a class="reference internal" href="#arbitrary-conversion-values">Arbitrary Conversion Values</a></li> <li><a class="reference internal" href="#removing-conv-from-interpolation">Removing <code class="docutils literal notranslate"><span class="pre">conv</span></code> From <code class="docutils literal notranslate"><span class="pre">Interpolation</span></code></a></li> <li><a class="reference internal" href="#alternate-interpolation-symbols">Alternate Interpolation Symbols</a></li> <li><a class="reference internal" href="#alternate-layouts-for-template">Alternate Layouts for <code class="docutils literal notranslate"><span class="pre">Template</span></code></a></li> <li><a class="reference internal" href="#mechanism-to-describe-the-kind-of-template">Mechanism to Describe the “Kind” of Template</a></li> <li><a class="reference internal" href="#binary-template-strings">Binary Template Strings</a></li> </ul> </li> <li><a class="reference internal" href="#acknowledgements">Acknowledgements</a></li> <li><a class="reference internal" href="#copyright">Copyright</a></li> </ul> <br> <a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0750.rst">Page Source (GitHub)</a> </nav> </section> <script src="../_static/colour_scheme.js"></script> <script src="../_static/wrap_tables.js"></script> <script src="../_static/sticky_banner.js"></script> </body> </html>