python-peps/pep-3140/index.html

322 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 3140 str(container) should call str(item), not repr(item) | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-3140/">
<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 3140 str(container) should call str(item), not repr(item) | peps.python.org'>
<meta property="og:description" content="This document discusses the advantages and disadvantages of the current implementation of str(container). It also discusses the pros and cons of a different approach - to call str(item) instead of repr(item).">
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-3140/">
<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 document discusses the advantages and disadvantages of the current implementation of str(container). It also discusses the pros and cons of a different approach - to call str(item) instead of repr(item).">
<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 3140</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 3140 str(container) should call str(item), not repr(item)</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Oleg Broytman &lt;phd&#32;&#97;t&#32;phdru.name&gt;,
Jim J. Jewett &lt;jimjjewett&#32;&#97;t&#32;gmail.com&gt;</dd>
<dt class="field-even">Discussions-To<span class="colon">:</span></dt>
<dd class="field-even"><a class="reference external" href="https://mail.python.org/pipermail/python-3000/">Python-3000 list</a></dd>
<dt class="field-odd">Status<span class="colon">:</span></dt>
<dd class="field-odd"><abbr title="Formally declined and will not be accepted">Rejected</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">27-May-2008</dd>
<dt class="field-even">Post-History<span class="colon">:</span></dt>
<dd class="field-even">28-May-2008</dd>
</dl>
<hr class="docutils" />
<section id="contents">
<details><summary>Table of Contents</summary><ul class="simple">
<li><a class="reference internal" href="#rejection">Rejection</a></li>
<li><a class="reference internal" href="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#motivation">Motivation</a></li>
<li><a class="reference internal" href="#current-situation">Current situation</a></li>
<li><a class="reference internal" href="#a-different-approach-call-str-item">A different approach - call <code class="docutils literal notranslate"><span class="pre">str(item)</span></code></a></li>
<li><a class="reference internal" href="#backward-compatibility">Backward compatibility</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="rejection">
<h2><a class="toc-backref" href="#rejection" role="doc-backlink">Rejection</a></h2>
<p>Guido said this would cause too much disturbance too close to beta. See <a class="footnote-reference brackets" href="#id2" id="id1">[1]</a>.</p>
</section>
<section id="abstract">
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
<p>This document discusses the advantages and disadvantages of the
current implementation of <code class="docutils literal notranslate"><span class="pre">str(container)</span></code>. It also discusses the
pros and cons of a different approach - to call <code class="docutils literal notranslate"><span class="pre">str(item)</span></code> instead
of <code class="docutils literal notranslate"><span class="pre">repr(item)</span></code>.</p>
</section>
<section id="motivation">
<h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2>
<p>Currently <code class="docutils literal notranslate"><span class="pre">str(container)</span></code> calls <code class="docutils literal notranslate"><span class="pre">repr</span></code> on items. Arguments for it:</p>
<ul class="simple">
<li>containers refuse to guess what the user wants to see on
<code class="docutils literal notranslate"><span class="pre">str(container)</span></code> - surroundings, delimiters, and so on;</li>
<li><code class="docutils literal notranslate"><span class="pre">repr(item)</span></code> usually displays type information - apostrophes
around strings, class names, etc.</li>
</ul>
<p>Arguments against:</p>
<ul class="simple">
<li>its illogical; <code class="docutils literal notranslate"><span class="pre">str()</span></code> is expected to call <code class="docutils literal notranslate"><span class="pre">__str__</span></code> if it exists,
not <code class="docutils literal notranslate"><span class="pre">__repr__</span></code>;</li>
<li>there is no standard way to print a containers content calling
items <code class="docutils literal notranslate"><span class="pre">__str__</span></code>, thats inconvenient in cases where <code class="docutils literal notranslate"><span class="pre">__str__</span></code> and
<code class="docutils literal notranslate"><span class="pre">__repr__</span></code> return different results;</li>
<li><code class="docutils literal notranslate"><span class="pre">repr(item)</span></code> sometimes do wrong things (hex-escapes non-ASCII strings,
e.g.)</li>
</ul>
<p>This PEP proposes to change how <code class="docutils literal notranslate"><span class="pre">str(container)</span></code> works. It is
proposed to mimic how <code class="docutils literal notranslate"><span class="pre">repr(container)</span></code> works except one detail - call
<code class="docutils literal notranslate"><span class="pre">str</span></code> on items instead of <code class="docutils literal notranslate"><span class="pre">repr</span></code>. This allows a user to choose
what results she want to get - from <code class="docutils literal notranslate"><span class="pre">item.__repr__</span></code> or <code class="docutils literal notranslate"><span class="pre">item.__str__</span></code>.</p>
</section>
<section id="current-situation">
<h2><a class="toc-backref" href="#current-situation" role="doc-backlink">Current situation</a></h2>
<p>Most container types (tuples, lists, dicts, sets, etc.) do not
implement <code class="docutils literal notranslate"><span class="pre">__str__</span></code> method, so <code class="docutils literal notranslate"><span class="pre">str(container)</span></code> calls
<code class="docutils literal notranslate"><span class="pre">container.__repr__</span></code>, and <code class="docutils literal notranslate"><span class="pre">container.__repr__</span></code>, once called, forgets
it is called from <code class="docutils literal notranslate"><span class="pre">str</span></code> and always calls <code class="docutils literal notranslate"><span class="pre">repr</span></code> on the containers
items.</p>
<p>This behaviour has advantages and disadvantages. One advantage is
that most items are represented with type information - strings
are surrounded by apostrophes, instances may have both class name
and instance data:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">([</span><span class="mi">42</span><span class="p">,</span> <span class="s1">&#39;42&#39;</span><span class="p">])</span>
<span class="go">[42, &#39;42&#39;]</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">([</span><span class="n">Decimal</span><span class="p">(</span><span class="s1">&#39;42&#39;</span><span class="p">),</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()])</span>
<span class="go">[Decimal(&quot;42&quot;), datetime.datetime(2008, 5, 27, 19, 57, 43, 485028)]</span>
</pre></div>
</div>
<p>The disadvantage is that <code class="docutils literal notranslate"><span class="pre">__repr__</span></code> often returns technical data
(like <code class="docutils literal notranslate"><span class="pre">&lt;object</span> <span class="pre">at</span> <span class="pre">address&gt;</span></code>) or unreadable string (hex-encoded
string if the input is non-ASCII string):</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">([</span><span class="s1">&#39;тест&#39;</span><span class="p">])</span>
<span class="go">[&#39;\xd4\xc5\xd3\xd4&#39;]</span>
</pre></div>
</div>
<p>One of the motivations for <a class="pep reference internal" href="../pep-3138/" title="PEP 3138 String representation in Python 3000">PEP 3138</a> is that neither <code class="docutils literal notranslate"><span class="pre">repr</span></code> nor <code class="docutils literal notranslate"><span class="pre">str</span></code>
will allow the sensible printing of dicts whose keys are non-ASCII
text strings. Now that Unicode identifiers are allowed, it
includes Pythons own attribute dicts. This also includes JSON
serialization (and caused some hoops for the json lib).</p>
<p><a class="pep reference internal" href="../pep-3138/" title="PEP 3138 String representation in Python 3000">PEP 3138</a> proposes to fix this by breaking the “repr is safe ASCII”
invariant, and changing the way <code class="docutils literal notranslate"><span class="pre">repr</span></code> (which is used for
persistence) outputs some objects, with system-dependent failures.</p>
<p>Changing how <code class="docutils literal notranslate"><span class="pre">str(container)</span></code> works would allow easy debugging in
the normal case, and retain the safety of ASCII-only for the
machine-readable case. The only downside is that <code class="docutils literal notranslate"><span class="pre">str(x)</span></code> and
<code class="docutils literal notranslate"><span class="pre">repr(x)</span></code> would more often be different but only in those cases
where the current almost-the-same version is insufficient.</p>
<p>It also seems illogical that <code class="docutils literal notranslate"><span class="pre">str(container)</span></code> calls <code class="docutils literal notranslate"><span class="pre">repr</span></code> on items
instead of <code class="docutils literal notranslate"><span class="pre">str</span></code>. Its only logical to expect following code:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Test</span><span class="p">:</span>
<span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="s2">&quot;STR&quot;</span>
<span class="k">def</span> <span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="s2">&quot;REPR&quot;</span>
<span class="n">test</span> <span class="o">=</span> <span class="n">Test</span><span class="p">()</span>
<span class="nb">print</span><span class="p">(</span><span class="n">test</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="nb">repr</span><span class="p">(</span><span class="n">test</span><span class="p">))</span>
<span class="nb">print</span><span class="p">([</span><span class="n">test</span><span class="p">])</span>
<span class="nb">print</span><span class="p">(</span><span class="nb">str</span><span class="p">([</span><span class="n">test</span><span class="p">]))</span>
</pre></div>
</div>
<p>to print:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">STR</span>
<span class="n">REPR</span>
<span class="p">[</span><span class="n">STR</span><span class="p">]</span>
<span class="p">[</span><span class="n">STR</span><span class="p">]</span>
</pre></div>
</div>
<p>where it actually prints:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">STR</span>
<span class="n">REPR</span>
<span class="p">[</span><span class="n">REPR</span><span class="p">]</span>
<span class="p">[</span><span class="n">REPR</span><span class="p">]</span>
</pre></div>
</div>
<p>Especially it is illogical to see that print in Python 2 uses <code class="docutils literal notranslate"><span class="pre">str</span></code>
if it is called on what seems to be a tuple:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span> <span class="n">Decimal</span><span class="p">(</span><span class="s1">&#39;42&#39;</span><span class="p">),</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span>
<span class="go">42 2008-05-27 20:16:22.534285</span>
</pre></div>
</div>
<p>where on an actual tuple it prints:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span><span class="p">((</span><span class="n">Decimal</span><span class="p">(</span><span class="s1">&#39;42&#39;</span><span class="p">),</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()))</span>
<span class="go">(Decimal(&quot;42&quot;), datetime.datetime(2008, 5, 27, 20, 16, 27, 937911))</span>
</pre></div>
</div>
</section>
<section id="a-different-approach-call-str-item">
<h2><a class="toc-backref" href="#a-different-approach-call-str-item" role="doc-backlink">A different approach - call <code class="docutils literal notranslate"><span class="pre">str(item)</span></code></a></h2>
<p>For example, with numbers it is often only the value that people
care about.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span> <span class="n">Decimal</span><span class="p">(</span><span class="s1">&#39;3&#39;</span><span class="p">)</span>
<span class="go">3</span>
</pre></div>
</div>
<p>But putting the value in a list forces users to read the type
information, exactly as if <code class="docutils literal notranslate"><span class="pre">repr</span></code> had been called for the benefit of
a machine:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span> <span class="p">[</span><span class="n">Decimal</span><span class="p">(</span><span class="s1">&#39;3&#39;</span><span class="p">)]</span>
<span class="go">[Decimal(&quot;3&quot;)]</span>
</pre></div>
</div>
<p>After this change, the type information would not clutter the <code class="docutils literal notranslate"><span class="pre">str</span></code>
output:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span> <span class="s2">&quot;</span><span class="si">%s</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">([</span><span class="n">Decimal</span><span class="p">(</span><span class="s1">&#39;3&#39;</span><span class="p">)])</span>
<span class="go">[3]</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">str</span><span class="p">([</span><span class="n">Decimal</span><span class="p">(</span><span class="s1">&#39;3&#39;</span><span class="p">)])</span> <span class="c1"># ==</span>
<span class="go">[3]</span>
</pre></div>
</div>
<p>But it would still be available if desired:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="nb">print</span> <span class="s2">&quot;</span><span class="si">%r</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">([</span><span class="n">Decimal</span><span class="p">(</span><span class="s1">&#39;3&#39;</span><span class="p">)])</span>
<span class="go">[Decimal(&#39;3&#39;)]</span>
<span class="gp">&gt;&gt;&gt; </span><span class="nb">repr</span><span class="p">([</span><span class="n">Decimal</span><span class="p">(</span><span class="s1">&#39;3&#39;</span><span class="p">)])</span> <span class="c1"># ==</span>
<span class="go">[Decimal(&#39;3&#39;)]</span>
</pre></div>
</div>
<p>There is a number of strategies to fix the problem. The most
radical is to change <code class="docutils literal notranslate"><span class="pre">__repr__</span></code> so it accepts a new parameter (flag)
“called from <code class="docutils literal notranslate"><span class="pre">str</span></code>, so call <code class="docutils literal notranslate"><span class="pre">str</span></code> on items, not <code class="docutils literal notranslate"><span class="pre">repr</span></code>”. The
drawback of the proposal is that every <code class="docutils literal notranslate"><span class="pre">__repr__</span></code> implementation
must be changed. Introspection could help a bit (inspect <code class="docutils literal notranslate"><span class="pre">__repr__</span></code>
before calling if it accepts 2 or 3 parameters), but introspection
doesnt work on classes written in C, like all built-in containers.</p>
<p>Less radical proposal is to implement <code class="docutils literal notranslate"><span class="pre">__str__</span></code> methods for built-in
container types. The obvious drawback is a duplication of effort - all
those <code class="docutils literal notranslate"><span class="pre">__str__</span></code> and <code class="docutils literal notranslate"><span class="pre">__repr__</span></code> implementations are only differ
in one small detail - if they call <code class="docutils literal notranslate"><span class="pre">str</span></code> or <code class="docutils literal notranslate"><span class="pre">repr</span></code> on items.</p>
<p>The most conservative proposal is not to change str at all but
to allow developers to implement their own application- or
library-specific pretty-printers. The drawback is again
a multiplication of effort and proliferation of many small
specific container-traversal algorithms.</p>
</section>
<section id="backward-compatibility">
<h2><a class="toc-backref" href="#backward-compatibility" role="doc-backlink">Backward compatibility</a></h2>
<p>In those cases where type information is more important than
usual, it will still be possible to get the current results by
calling <code class="docutils literal notranslate"><span class="pre">repr</span></code> explicitly.</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="id2" role="doc-footnote">
<dt class="label" id="id2">[<a href="#id1">1</a>]</dt>
<dd>Guido van Rossum, PEP: str(container) should call str(item), not
repr(item)
<a class="reference external" href="https://mail.python.org/pipermail/python-3000/2008-May/013876.html">https://mail.python.org/pipermail/python-3000/2008-May/013876.html</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-3140.rst">https://github.com/python/peps/blob/main/peps/pep-3140.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-3140.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="#rejection">Rejection</a></li>
<li><a class="reference internal" href="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#motivation">Motivation</a></li>
<li><a class="reference internal" href="#current-situation">Current situation</a></li>
<li><a class="reference internal" href="#a-different-approach-call-str-item">A different approach - call <code class="docutils literal notranslate"><span class="pre">str(item)</span></code></a></li>
<li><a class="reference internal" href="#backward-compatibility">Backward compatibility</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-3140.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>