python-peps/pep-0292/index.html

318 lines
25 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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 292 Simpler String Substitutions | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-0292/">
<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 292 Simpler String Substitutions | peps.python.org'>
<meta property="og:description" content="This PEP describes a simpler string substitution feature, also known as string interpolation. This PEP is “simpler” in two respects:">
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-0292/">
<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 describes a simpler string substitution feature, also known as string interpolation. This PEP is “simpler” in two respects:">
<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> &raquo; </li>
<li><a href="../pep-0000/">PEP Index</a> &raquo; </li>
<li>PEP 292</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 292 Simpler String Substitutions</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Barry Warsaw &lt;barry&#32;&#97;t&#32;python.org&gt;</dd>
<dt class="field-even">Status<span class="colon">:</span></dt>
<dd class="field-even"><abbr title="Accepted and implementation complete, or no longer active">Final</abbr></dd>
<dt class="field-odd">Type<span class="colon">:</span></dt>
<dd class="field-odd"><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-even">Created<span class="colon">:</span></dt>
<dd class="field-even">18-Jun-2002</dd>
<dt class="field-odd">Python-Version<span class="colon">:</span></dt>
<dd class="field-odd">2.4</dd>
<dt class="field-even">Post-History<span class="colon">:</span></dt>
<dd class="field-even">18-Jun-2002, 23-Mar-2004, 22-Aug-2004</dd>
<dt class="field-odd">Replaces<span class="colon">:</span></dt>
<dd class="field-odd"><a class="reference external" href="../pep-0215/">215</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="#rationale">Rationale</a></li>
<li><a class="reference internal" href="#a-simpler-proposal">A Simpler Proposal</a></li>
<li><a class="reference internal" href="#why-and-braces">Why <code class="docutils literal notranslate"><span class="pre">$</span></code> and Braces?</a></li>
<li><a class="reference internal" href="#comparison-to-pep-215">Comparison to PEP 215</a></li>
<li><a class="reference internal" href="#internationalization">Internationalization</a></li>
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li>
<li><a class="reference internal" href="#references">References</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 describes a simpler string substitution feature, also
known as string interpolation. This PEP is “simpler” in two
respects:</p>
<ol class="arabic simple">
<li>Pythons current string substitution feature
(i.e. <code class="docutils literal notranslate"><span class="pre">%</span></code>-substitution) is complicated and error prone. This PEP
is simpler at the cost of some expressiveness.</li>
<li><a class="pep reference internal" href="../pep-0215/" title="PEP 215 String Interpolation">PEP 215</a> proposed an alternative string interpolation feature,
introducing a new <code class="docutils literal notranslate"><span class="pre">$</span></code> string prefix. <a class="pep reference internal" href="../pep-0292/" title="PEP 292 Simpler String Substitutions">PEP 292</a> is simpler than
this because it involves no syntax changes and has much simpler
rules for what substitutions can occur in the string.</li>
</ol>
</section>
<section id="rationale">
<h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2>
<p>Python currently supports a string substitution syntax based on
Cs <code class="docutils literal notranslate"><span class="pre">printf()</span></code> <code class="docutils literal notranslate"><span class="pre">%</span></code> formatting character <a class="footnote-reference brackets" href="#id5" id="id1">[1]</a>. While quite rich,
<code class="docutils literal notranslate"><span class="pre">%</span></code>-formatting codes are also error prone, even for
experienced Python programmers. A common mistake is to leave off
the trailing format character, e.g. the <code class="docutils literal notranslate"><span class="pre">s</span></code> in <code class="docutils literal notranslate"><span class="pre">&quot;%(name)s&quot;</span></code>.</p>
<p>In addition, the rules for what can follow a <code class="docutils literal notranslate"><span class="pre">%</span></code> sign are fairly
complex, while the usual application rarely needs such complexity.
Most scripts need to do some string interpolation, but most of
those use simple stringification formats, i.e. <code class="docutils literal notranslate"><span class="pre">%s</span></code> or <code class="docutils literal notranslate"><span class="pre">%(name)s</span></code>
This form should be made simpler and less error prone.</p>
</section>
<section id="a-simpler-proposal">
<h2><a class="toc-backref" href="#a-simpler-proposal" role="doc-backlink">A Simpler Proposal</a></h2>
<p>We propose the addition of a new class, called <code class="docutils literal notranslate"><span class="pre">Template</span></code>, which
will live in the string module. The <code class="docutils literal notranslate"><span class="pre">Template</span></code> class supports new
rules for string substitution; its value contains placeholders,
introduced with the <code class="docutils literal notranslate"><span class="pre">$</span></code> character. The following rules for
<code class="docutils literal notranslate"><span class="pre">$</span></code>-placeholders apply:</p>
<ol class="arabic simple">
<li><code class="docutils literal notranslate"><span class="pre">$$</span></code> is an escape; it is replaced with a single <code class="docutils literal notranslate"><span class="pre">$</span></code></li>
<li><code class="docutils literal notranslate"><span class="pre">$identifier</span></code> names a substitution placeholder matching a mapping
key of “identifier”. By default, “identifier” must spell a
Python identifier as defined in <a class="footnote-reference brackets" href="#id6" id="id2">[2]</a>. The first non-identifier
character after the <code class="docutils literal notranslate"><span class="pre">$</span></code> character terminates this placeholder
specification.</li>
<li><code class="docutils literal notranslate"><span class="pre">${identifier}</span></code> is equivalent to <code class="docutils literal notranslate"><span class="pre">$identifier</span></code>. It is required
when valid identifier characters follow the placeholder but are
not part of the placeholder, e.g. <code class="docutils literal notranslate"><span class="pre">&quot;${noun}ification&quot;</span></code>.</li>
</ol>
<p>If the <code class="docutils literal notranslate"><span class="pre">$</span></code> character appears at the end of the line, or is followed
by any other character than those described above, a <code class="docutils literal notranslate"><span class="pre">ValueError</span></code>
will be raised at interpolation time. Values in mapping are
converted automatically to strings.</p>
<p>No other characters have special meaning, however it is possible
to derive from the <code class="docutils literal notranslate"><span class="pre">Template</span></code> class to define different substitution
rules. For example, a derived class could allow for periods in
the placeholder (e.g. to support a kind of dynamic namespace and
attribute path lookup), or could define a delimiter character
other than <code class="docutils literal notranslate"><span class="pre">$</span></code>.</p>
<p>Once the <code class="docutils literal notranslate"><span class="pre">Template</span></code> has been created, substitutions can be performed
by calling one of two methods:</p>
<ul>
<li><code class="docutils literal notranslate"><span class="pre">substitute()</span></code>. This method returns a new string which results
when the values of a mapping are substituted for the
placeholders in the <code class="docutils literal notranslate"><span class="pre">Template</span></code>. If there are placeholders which
are not present in the mapping, a <code class="docutils literal notranslate"><span class="pre">KeyError</span></code> will be raised.</li>
<li><code class="docutils literal notranslate"><span class="pre">safe_substitute()</span></code>. This is similar to the <code class="docutils literal notranslate"><span class="pre">substitute()</span></code> method,
except that <code class="docutils literal notranslate"><span class="pre">KeyErrors</span></code> are never raised (due to placeholders
missing from the mapping). When a placeholder is missing, the
original placeholder will appear in the resulting string.<p>Here are some examples:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">string</span> <span class="kn">import</span> <span class="n">Template</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">s</span> <span class="o">=</span> <span class="n">Template</span><span class="p">(</span><span class="s1">&#39;$</span><span class="si">{name}</span><span class="s1"> was born in $</span><span class="si">{country}</span><span class="s1">&#39;</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span> <span class="n">s</span><span class="o">.</span><span class="n">substitute</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Guido&#39;</span><span class="p">,</span> <span class="n">country</span><span class="o">=</span><span class="s1">&#39;the Netherlands&#39;</span><span class="p">)</span>
<span class="go">Guido was born in the Netherlands</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span> <span class="n">s</span><span class="o">.</span><span class="n">substitute</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Guido&#39;</span><span class="p">)</span>
<span class="gt">Traceback (most recent call last):</span>
<span class="gr">[...]</span>
<span class="gr">KeyError</span>: <span class="n">&#39;country&#39;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span> <span class="n">s</span><span class="o">.</span><span class="n">safe_substitute</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">&#39;Guido&#39;</span><span class="p">)</span>
<span class="go">Guido was born in ${country}</span>
</pre></div>
</div>
</li>
</ul>
<p>The signature of <code class="docutils literal notranslate"><span class="pre">substitute()</span></code> and <code class="docutils literal notranslate"><span class="pre">safe_substitute()</span></code> allows for
passing the mapping of placeholders to values, either as a single
dictionary-like object in the first positional argument, or as
keyword arguments as shown above. The exact details and
signatures of these two methods is reserved for the standard
library documentation.</p>
</section>
<section id="why-and-braces">
<h2><a class="toc-backref" href="#why-and-braces" role="doc-backlink">Why <code class="docutils literal notranslate"><span class="pre">$</span></code> and Braces?</a></h2>
<p>The BDFL said it best <a class="footnote-reference brackets" href="#id7" id="id3">[3]</a>: “The <code class="docutils literal notranslate"><span class="pre">$</span></code> means “substitution” in so many
languages besides Perl that I wonder where youve been. […]
Were copying this from the shell.”</p>
<p>Thus the substitution rules are chosen because of the similarity
with so many other languages. This makes the substitution rules
easier to teach, learn, and remember.</p>
</section>
<section id="comparison-to-pep-215">
<h2><a class="toc-backref" href="#comparison-to-pep-215" role="doc-backlink">Comparison to PEP 215</a></h2>
<p><a class="pep reference internal" href="../pep-0215/" title="PEP 215 String Interpolation">PEP 215</a> describes an alternate proposal for string interpolation.
Unlike that PEP, this one does not propose any new syntax for
Python. All the proposed new features are embodied in a new
library module. <a class="pep reference internal" href="../pep-0215/" title="PEP 215 String Interpolation">PEP 215</a> proposes a new string prefix
representation such as <code class="docutils literal notranslate"><span class="pre">$&quot;&quot;</span></code> which signal to Python that a new type
of string is present. <code class="docutils literal notranslate"><span class="pre">$</span></code>-strings would have to interact with the
existing r-prefixes and u-prefixes, essentially doubling the
number of string prefix combinations.</p>
<p><a class="pep reference internal" href="../pep-0215/" title="PEP 215 String Interpolation">PEP 215</a> also allows for arbitrary Python expressions inside the
<code class="docutils literal notranslate"><span class="pre">$</span></code>-strings, so that you could do things like:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>import sys
print $&quot;sys = $sys, sys = $sys.modules[&#39;sys&#39;]&quot;
</pre></div>
</div>
<p>which would return:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">sys</span> <span class="o">=</span> <span class="o">&lt;</span><span class="n">module</span> <span class="s1">&#39;sys&#39;</span> <span class="p">(</span><span class="n">built</span><span class="o">-</span><span class="ow">in</span><span class="p">)</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">sys</span> <span class="o">=</span> <span class="o">&lt;</span><span class="n">module</span> <span class="s1">&#39;sys&#39;</span> <span class="p">(</span><span class="n">built</span><span class="o">-</span><span class="ow">in</span><span class="p">)</span><span class="o">&gt;</span>
</pre></div>
</div>
<p>Its generally accepted that the rules in <a class="pep reference internal" href="../pep-0215/" title="PEP 215 String Interpolation">PEP 215</a> are safe in the
sense that they introduce no new security issues (see <a class="pep reference internal" href="../pep-0215/" title="PEP 215 String Interpolation">PEP 215</a>,
“Security Issues” for details). However, the rules are still
quite complex, and make it more difficult to see the substitution
placeholder in the original <code class="docutils literal notranslate"><span class="pre">$</span></code>-string.</p>
<p>The interesting thing is that the <code class="docutils literal notranslate"><span class="pre">Template</span></code> class defined in this
PEP is designed for inheritance and, with a little extra work,
its possible to support <a class="pep reference internal" href="../pep-0215/" title="PEP 215 String Interpolation">PEP 215</a>s functionality using existing
Python syntax.</p>
<p>For example, one could define subclasses of <code class="docutils literal notranslate"><span class="pre">Template</span></code> and dict that
allowed for a more complex placeholder syntax and a mapping that
evaluated those placeholders.</p>
</section>
<section id="internationalization">
<h2><a class="toc-backref" href="#internationalization" role="doc-backlink">Internationalization</a></h2>
<p>The implementation supports internationalization by recording the
original template string in the <code class="docutils literal notranslate"><span class="pre">Template</span></code> instances <code class="docutils literal notranslate"><span class="pre">template</span></code>
attribute. This attribute would serve as the lookup key in an
gettext-based catalog. It is up to the application to turn the
resulting string back into a <code class="docutils literal notranslate"><span class="pre">Template</span></code> for substitution.</p>
<p>However, the <code class="docutils literal notranslate"><span class="pre">Template</span></code> class was designed to work more intuitively
in an internationalized application, by supporting the mixing-in
of <code class="docutils literal notranslate"><span class="pre">Template</span></code> and unicode subclasses. Thus an internationalized
application could create an application-specific subclass,
multiply inheriting from <code class="docutils literal notranslate"><span class="pre">Template</span></code> and unicode, and using instances
of that subclass as the gettext catalog key. Further, the
subclass could alias the special <code class="docutils literal notranslate"><span class="pre">__mod__()</span></code> method to either
<code class="docutils literal notranslate"><span class="pre">.substitute()</span></code> or <code class="docutils literal notranslate"><span class="pre">.safe_substitute()</span></code> to provide a more traditional
string/unicode like <code class="docutils literal notranslate"><span class="pre">%</span></code>-operator substitution syntax.</p>
</section>
<section id="reference-implementation">
<h2><a class="toc-backref" href="#reference-implementation" role="doc-backlink">Reference Implementation</a></h2>
<p>The implementation <a class="footnote-reference brackets" href="#id8" id="id4">[4]</a> has been committed to the Python 2.4 source tree.</p>
</section>
<section id="references">
<h2><a class="toc-backref" href="#references" role="doc-backlink">References</a></h2>
<aside class="footnote-list brackets">
<aside class="footnote brackets" id="id5" role="doc-footnote">
<dt class="label" id="id5">[<a href="#id1">1</a>]</dt>
<dd>String Formatting Operations
<a class="reference external" href="https://docs.python.org/release/2.6/library/stdtypes.html#string-formatting-operations">https://docs.python.org/release/2.6/library/stdtypes.html#string-formatting-operations</a></aside>
<aside class="footnote brackets" id="id6" role="doc-footnote">
<dt class="label" id="id6">[<a href="#id2">2</a>]</dt>
<dd>Identifiers and Keywords
<a class="reference external" href="https://docs.python.org/release/2.6/reference/lexical_analysis.html#identifiers-and-keywords">https://docs.python.org/release/2.6/reference/lexical_analysis.html#identifiers-and-keywords</a></aside>
<aside class="footnote brackets" id="id7" role="doc-footnote">
<dt class="label" id="id7">[<a href="#id3">3</a>]</dt>
<dd><a class="reference external" href="https://mail.python.org/pipermail/python-dev/2002-June/025652.html">https://mail.python.org/pipermail/python-dev/2002-June/025652.html</a></aside>
<aside class="footnote brackets" id="id8" role="doc-footnote">
<dt class="label" id="id8">[<a href="#id4">4</a>]</dt>
<dd>Reference Implementation
<a class="reference external" href="http://sourceforge.net/tracker/index.php?func=detail&amp;aid=1014055&amp;group_id=5470&amp;atid=305470">http://sourceforge.net/tracker/index.php?func=detail&amp;aid=1014055&amp;group_id=5470&amp;atid=305470</a></aside>
</aside>
</section>
<section id="copyright">
<h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2>
<p>This document has been placed in the public domain.</p>
</section>
</section>
<hr class="docutils" />
<p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0292.rst">https://github.com/python/peps/blob/main/peps/pep-0292.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0292.rst">2023-09-09 17:39:29 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="#rationale">Rationale</a></li>
<li><a class="reference internal" href="#a-simpler-proposal">A Simpler Proposal</a></li>
<li><a class="reference internal" href="#why-and-braces">Why <code class="docutils literal notranslate"><span class="pre">$</span></code> and Braces?</a></li>
<li><a class="reference internal" href="#comparison-to-pep-215">Comparison to PEP 215</a></li>
<li><a class="reference internal" href="#internationalization">Internationalization</a></li>
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li>
<li><a class="reference internal" href="#references">References</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-0292.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>