CINXE.COM
PEP 303 – Extend divmod() for Multiple Divisors | 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 303 – Extend divmod() for Multiple Divisors | peps.python.org</title> <link rel="shortcut icon" href="../_static/py.png"> <link rel="canonical" href="https://peps.python.org/pep-0303/"> <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 303 – Extend divmod() for Multiple Divisors | peps.python.org'> <meta property="og:description" content="This PEP describes an extension to the built-in divmod() function, allowing it to take multiple divisors, chaining several calls to divmod() into one."> <meta property="og:type" content="website"> <meta property="og:url" content="https://peps.python.org/pep-0303/"> <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 an extension to the built-in divmod() function, allowing it to take multiple divisors, chaining several calls to divmod() into one."> <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 303</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 303 – Extend divmod() for Multiple Divisors</h1> <dl class="rfc2822 field-list simple"> <dt class="field-odd">Author<span class="colon">:</span></dt> <dd class="field-odd">Thomas Bellman <bellman+pep-divmod at lysator.liu.se></dd> <dt class="field-even">Status<span class="colon">:</span></dt> <dd class="field-even"><abbr title="Formally declined and will not be accepted">Rejected</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">31-Dec-2002</dd> <dt class="field-odd">Python-Version<span class="colon">:</span></dt> <dd class="field-odd">2.3</dd> <dt class="field-even">Post-History<span class="colon">:</span></dt> <dd class="field-even"><p></p></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="#pronouncement">Pronouncement</a></li> <li><a class="reference internal" href="#specification">Specification</a></li> <li><a class="reference internal" href="#motivation">Motivation</a></li> <li><a class="reference internal" href="#rationale">Rationale</a></li> <li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</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 an extension to the built-in <code class="docutils literal notranslate"><span class="pre">divmod()</span></code> function, allowing it to take multiple divisors, chaining several calls to <code class="docutils literal notranslate"><span class="pre">divmod()</span></code> into one.</p> </section> <section id="pronouncement"> <h2><a class="toc-backref" href="#pronouncement" role="doc-backlink">Pronouncement</a></h2> <p>This PEP is rejected. Most uses for chained <code class="docutils literal notranslate"><span class="pre">divmod()</span></code> involve a constant modulus (in radix conversions for example) and are more properly coded as a loop. The example of splitting seconds into days/hours/minutes/seconds does not generalize to months and years; rather, the whole use case is handled more flexibly and robustly by date and time modules. The other use cases mentioned in the PEP are somewhat rare in real code. The proposal is also problematic in terms of clarity and obviousness. In the examples, it is not immediately clear that the argument order is correct or that the target tuple is of the right length. Users from other languages are more likely to understand the standard two argument form without having to re-read the documentation. See python-dev discussion on 17 June 2005 <a class="footnote-reference brackets" href="#id2" id="id1">[1]</a>.</p> </section> <section id="specification"> <h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2> <p>The built-in <code class="docutils literal notranslate"><span class="pre">divmod()</span></code> function would be changed to accept multiple divisors, changing its signature from <code class="docutils literal notranslate"><span class="pre">divmod(dividend,</span> <span class="pre">divisor)</span></code> to <code class="docutils literal notranslate"><span class="pre">divmod(dividend,</span> <span class="pre">*divisors)</span></code>. The dividend is divided by the last divisor, giving a quotient and a remainder. The quotient is then divided by the second to last divisor, giving a new quotient and remainder. This is repeated until all divisors have been used, and <code class="docutils literal notranslate"><span class="pre">divmod()</span></code> then returns a tuple consisting of the quotient from the last step, and the remainders from all the steps.</p> <p>A Python implementation of the new <code class="docutils literal notranslate"><span class="pre">divmod()</span></code> behaviour could look like:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">divmod</span><span class="p">(</span><span class="n">dividend</span><span class="p">,</span> <span class="o">*</span><span class="n">divisors</span><span class="p">):</span> <span class="n">modulos</span> <span class="o">=</span> <span class="p">()</span> <span class="n">q</span> <span class="o">=</span> <span class="n">dividend</span> <span class="k">while</span> <span class="n">divisors</span><span class="p">:</span> <span class="n">q</span><span class="p">,</span> <span class="n">r</span> <span class="o">=</span> <span class="n">q</span><span class="o">.</span><span class="fm">__divmod__</span><span class="p">(</span><span class="n">divisors</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span> <span class="n">modulos</span> <span class="o">=</span> <span class="p">(</span><span class="n">r</span><span class="p">,)</span> <span class="o">+</span> <span class="n">modulos</span> <span class="n">divisors</span> <span class="o">=</span> <span class="n">divisors</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="k">return</span> <span class="p">(</span><span class="n">q</span><span class="p">,)</span> <span class="o">+</span> <span class="n">modulos</span> </pre></div> </div> </section> <section id="motivation"> <h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2> <p>Occasionally one wants to perform a chain of <code class="docutils literal notranslate"><span class="pre">divmod()</span></code> operations, calling <code class="docutils literal notranslate"><span class="pre">divmod()</span></code> on the quotient from the previous step, with varying divisors. The most common case is probably converting a number of seconds into weeks, days, hours, minutes and seconds. This would today be written as:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">secs_to_wdhms</span><span class="p">(</span><span class="n">seconds</span><span class="p">):</span> <span class="n">m</span><span class="p">,</span> <span class="n">s</span> <span class="o">=</span> <span class="nb">divmod</span><span class="p">(</span><span class="n">seconds</span><span class="p">,</span> <span class="mi">60</span><span class="p">)</span> <span class="n">h</span><span class="p">,</span> <span class="n">m</span> <span class="o">=</span> <span class="nb">divmod</span><span class="p">(</span><span class="n">m</span><span class="p">,</span> <span class="mi">60</span><span class="p">)</span> <span class="n">d</span><span class="p">,</span> <span class="n">h</span> <span class="o">=</span> <span class="nb">divmod</span><span class="p">(</span><span class="n">h</span><span class="p">,</span> <span class="mi">24</span><span class="p">)</span> <span class="n">w</span><span class="p">,</span> <span class="n">d</span> <span class="o">=</span> <span class="nb">divmod</span><span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="mi">7</span><span class="p">)</span> <span class="k">return</span> <span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="n">d</span><span class="p">,</span> <span class="n">h</span><span class="p">,</span> <span class="n">m</span><span class="p">,</span> <span class="n">s</span><span class="p">)</span> </pre></div> </div> <p>This is tedious and easy to get wrong each time you need it.</p> <p>If instead the <code class="docutils literal notranslate"><span class="pre">divmod()</span></code> built-in is changed according the proposal, the code for converting seconds to weeks, days, hours, minutes and seconds then become</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">secs_to_wdhms</span><span class="p">(</span><span class="n">seconds</span><span class="p">):</span> <span class="n">w</span><span class="p">,</span> <span class="n">d</span><span class="p">,</span> <span class="n">h</span><span class="p">,</span> <span class="n">m</span><span class="p">,</span> <span class="n">s</span> <span class="o">=</span> <span class="nb">divmod</span><span class="p">(</span><span class="n">seconds</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">24</span><span class="p">,</span> <span class="mi">60</span><span class="p">,</span> <span class="mi">60</span><span class="p">)</span> <span class="k">return</span> <span class="p">(</span><span class="n">w</span><span class="p">,</span> <span class="n">d</span><span class="p">,</span> <span class="n">h</span><span class="p">,</span> <span class="n">m</span><span class="p">,</span> <span class="n">s</span><span class="p">)</span> </pre></div> </div> <p>which is easier to type, easier to type correctly, and easier to read.</p> <p>Other applications are:</p> <ul class="simple"> <li>Astronomical angles (declination is measured in degrees, minutes and seconds, right ascension is measured in hours, minutes and seconds).</li> <li>Old British currency (1 pound = 20 shilling, 1 shilling = 12 pence).</li> <li>Anglo-Saxon length units: 1 mile = 1760 yards, 1 yard = 3 feet, 1 foot = 12 inches.</li> <li>Anglo-Saxon weight units: 1 long ton = 160 stone, 1 stone = 14 pounds, 1 pound = 16 ounce, 1 ounce = 16 dram.</li> <li>British volumes: 1 gallon = 4 quart, 1 quart = 2 pint, 1 pint = 20 fluid ounces.</li> </ul> </section> <section id="rationale"> <h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2> <p>The idea comes from APL, which has an operator that does this. (I don’t remember what the operator looks like, and it would probably be impossible to render in ASCII anyway.)</p> <p>The APL operator takes a list as its second operand, while this PEP proposes that each divisor should be a separate argument to the <code class="docutils literal notranslate"><span class="pre">divmod()</span></code> function. This is mainly because it is expected that the most common uses will have the divisors as constants right in the call (as the 7, 24, 60, 60 above), and adding a set of parentheses or brackets would just clutter the call.</p> <p>Requiring an explicit sequence as the second argument to <code class="docutils literal notranslate"><span class="pre">divmod()</span></code> would seriously break backwards compatibility. Making <code class="docutils literal notranslate"><span class="pre">divmod()</span></code> check its second argument for being a sequence is deemed to be too ugly to contemplate. And in the case where one <em>does</em> have a sequence that is computed other-where, it is easy enough to write <code class="docutils literal notranslate"><span class="pre">divmod(x,</span> <span class="pre">*divs)</span></code> instead.</p> <p>Requiring at least one divisor, i.e rejecting <code class="docutils literal notranslate"><span class="pre">divmod(x)</span></code>, has been considered, but no good reason to do so has come to mind, and is thus allowed in the name of generality.</p> <p>Calling <code class="docutils literal notranslate"><span class="pre">divmod()</span></code> with no divisors should still return a tuple (of one element). Code that calls <code class="docutils literal notranslate"><span class="pre">divmod()</span></code> with a varying number of divisors, and thus gets a return value with an “unknown” number of elements, would otherwise have to special case that case. Code that <em>knows</em> it is calling <code class="docutils literal notranslate"><span class="pre">divmod()</span></code> with no divisors is considered to be too silly to warrant a special case.</p> <p>Processing the divisors in the other direction, i.e dividing with the first divisor first, instead of dividing with the last divisor first, has been considered. However, the result comes with the most significant part first and the least significant part last (think of the chained divmod as a way of splitting a number into “digits”, with varying weights), and it is reasonable to specify the divisors (weights) in the same order as the result.</p> <p>The inverse operation:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">inverse_divmod</span><span class="p">(</span><span class="n">seq</span><span class="p">,</span> <span class="o">*</span><span class="n">factors</span><span class="p">):</span> <span class="n">product</span> <span class="o">=</span> <span class="n">seq</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">for</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">factors</span><span class="p">,</span> <span class="n">seq</span><span class="p">[</span><span class="mi">1</span><span class="p">:]):</span> <span class="n">product</span> <span class="o">=</span> <span class="n">product</span> <span class="o">*</span> <span class="n">x</span> <span class="o">+</span> <span class="n">y</span> <span class="k">return</span> <span class="n">product</span> </pre></div> </div> <p>could also be useful. However, writing</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">seconds</span> <span class="o">=</span> <span class="p">(((((</span><span class="n">w</span> <span class="o">*</span> <span class="mi">7</span><span class="p">)</span> <span class="o">+</span> <span class="n">d</span><span class="p">)</span> <span class="o">*</span> <span class="mi">24</span> <span class="o">+</span> <span class="n">h</span><span class="p">)</span> <span class="o">*</span> <span class="mi">60</span> <span class="o">+</span> <span class="n">m</span><span class="p">)</span> <span class="o">*</span> <span class="mi">60</span> <span class="o">+</span> <span class="n">s</span><span class="p">)</span> </pre></div> </div> <p>is less cumbersome both to write and to read than the chained divmods. It is therefore deemed to be less important, and its introduction can be deferred to its own PEP. Also, such a function needs a good name, and the PEP author has not managed to come up with one yet.</p> <p>Calling <code class="docutils literal notranslate"><span class="pre">divmod("spam")</span></code> does not raise an error, despite strings supporting neither division nor modulo. However, unless we know the other object too, we can’t determine whether <code class="docutils literal notranslate"><span class="pre">divmod()</span></code> would work or not, and thus it seems silly to forbid it.</p> </section> <section id="backwards-compatibility"> <h2><a class="toc-backref" href="#backwards-compatibility" role="doc-backlink">Backwards Compatibility</a></h2> <p>Any module that replaces the <code class="docutils literal notranslate"><span class="pre">divmod()</span></code> function in the <code class="docutils literal notranslate"><span class="pre">__builtin__</span></code> module, may cause other modules using the new syntax to break. It is expected that this is very uncommon.</p> <p>Code that expects a <code class="docutils literal notranslate"><span class="pre">TypeError</span></code> exception when calling <code class="docutils literal notranslate"><span class="pre">divmod()</span></code> with anything but two arguments will break. This is also expected to be very uncommon.</p> <p>No other issues regarding backwards compatibility are known.</p> </section> <section id="reference-implementation"> <h2><a class="toc-backref" href="#reference-implementation" role="doc-backlink">Reference Implementation</a></h2> <p>Not finished yet, but it seems a rather straightforward new implementation of the function <code class="docutils literal notranslate"><span class="pre">builtin_divmod()</span></code> in <code class="docutils literal notranslate"><span class="pre">Python/bltinmodule.c</span></code>.</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>Raymond Hettinger, “Propose rejection of PEP 303 – Extend divmod() for Multiple Divisors” <a class="reference external" href="https://mail.python.org/pipermail/python-dev/2005-June/054283.html">https://mail.python.org/pipermail/python-dev/2005-June/054283.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-0303.rst">https://github.com/python/peps/blob/main/peps/pep-0303.rst</a></p> <p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0303.rst">2025-02-01 08:59:27 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="#pronouncement">Pronouncement</a></li> <li><a class="reference internal" href="#specification">Specification</a></li> <li><a class="reference internal" href="#motivation">Motivation</a></li> <li><a class="reference internal" href="#rationale">Rationale</a></li> <li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</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-0303.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>