diff --git a/pep-0303.txt b/pep-0303.txt index 3e0a86200..dcc963f7e 100644 --- a/pep-0303.txt +++ b/pep-0303.txt @@ -5,192 +5,210 @@ Last-Modified: $Date$ Author: Thomas Bellman Status: Rejected Type: Standards Track -Content-Type: text/plain +Content-Type: text/x-rst Created: 31-Dec-2002 Python-Version: 2.3 Post-History: Abstract +======== + +This PEP describes an extension to the built-in ``divmod()`` function, +allowing it to take multiple divisors, chaining several calls to +``divmod()`` into one. - This PEP describes an extension to the built-in divmod() function, - allowing it to take multiple divisors, chaining several calls to - divmod() into one. Pronouncement +============= + +This PEP is rejected. Most uses for chained ``divmod()`` 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 [1]_. - This PEP is rejected. Most uses for chained divmod() 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. Specification +============= - The built-in divmod() function would be changed to accept multiple - divisors, changing its signature from divmod(dividend, divisor) to - divmod(dividend, *divisors). 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 divmod() then returns a tuple consisting of the quotient from - the last step, and the remainders from all the steps. +The built-in ``divmod()`` function would be changed to accept multiple +divisors, changing its signature from ``divmod(dividend, divisor)`` to +``divmod(dividend, divisors)``. 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 ``divmod()`` then returns a tuple consisting of the quotient from +the last step, and the remainders from all the steps. - A Python implementation of the new divmod() behaviour could look - like: +A Python implementation of the new ``divmod()`` behaviour could look +like:: - def divmod(dividend, *divisors): - modulos = () - q = dividend - while divisors: - q,r = q.__divmod__(divisors[-1]) - modulos = (r,) + modulos - divisors = divisors[:-1] - return (q,) + modulos + def divmod(dividend, *divisors): + modulos = () + q = dividend + while divisors: + q, r = q.__divmod__(divisors[-1]) + modulos = (r,) + modulos + divisors = divisors[:-1] + return (q,) + modulos Motivation +========== - Occasionally one wants to perform a chain of divmod() operations, - calling divmod() 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: +Occasionally one wants to perform a chain of ``divmod()`` operations, +calling ``divmod()`` 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:: - def secs_to_wdhms(seconds): - m,s = divmod(seconds, 60) - h,m = divmod(m, 60) - d,h = divmod(h, 24) - w,d = divmod(d, 7) - return (w,d,h,m,s) + def secs_to_wdhms(seconds): + m, s = divmod(seconds, 60) + h, m = divmod(m, 60) + d, h = divmod(h, 24) + w, d = divmod(d, 7) + return (w, d, h, m, s) - This is tedious and easy to get wrong each time you need it. +This is tedious and easy to get wrong each time you need it. - If instead the divmod() built-in is changed according the proposal, - the code for converting seconds to weeks, days, hours, minutes and - seconds then become +If instead the ``divmod()`` built-in is changed according the proposal, +the code for converting seconds to weeks, days, hours, minutes and +seconds then become:: - def secs_to_wdhms(seconds): - w,d,h,m,s = divmod(seconds, 7, 24, 60, 60) - return (w,d,h,m,s) + def secs_to_wdhms(seconds): + w, d, h, m, s = divmod(seconds, 7, 24, 60, 60) + return (w, d, h, m, s) - which is easier to type, easier to type correctly, and easier to - read. +which is easier to type, easier to type correctly, and easier to +read. - Other applications are: +Other applications are: - - Astronomical angles (declination is measured in degrees, minutes - and seconds, right ascension is measured in hours, minutes and - seconds). - - Old British currency (1 pound = 20 shilling, 1 shilling = 12 pence) - - Anglo-Saxon length units: 1 mile = 1760 yards, 1 yard = 3 feet, - 1 foot = 12 inches. - - Anglo-Saxon weight units: 1 long ton = 160 stone, 1 stone = 14 - pounds, 1 pound = 16 ounce, 1 ounce = 16 dram - - British volumes: 1 gallon = 4 quart, 1 quart = 2 pint, 1 pint - = 20 fluid ounces +- Astronomical angles (declination is measured in degrees, minutes + and seconds, right ascension is measured in hours, minutes and + seconds). +- Old British currency (1 pound = 20 shilling, 1 shilling = 12 pence) +- Anglo-Saxon length units: 1 mile = 1760 yards, 1 yard = 3 feet, + 1 foot = 12 inches. +- Anglo-Saxon weight units: 1 long ton = 160 stone, 1 stone = 14 + pounds, 1 pound = 16 ounce, 1 ounce = 16 dram +- British volumes: 1 gallon = 4 quart, 1 quart = 2 pint, 1 pint + = 20 fluid ounces Rationale +========= - 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.) +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.) - The APL operator takes a list as its second operand, while this - PEP proposes that each divisor should be a separate argument to - the divmod() 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. +The APL operator takes a list as its second operand, while this +PEP proposes that each divisor should be a separate argument to +the ``divmod()`` 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. - Requiring an explicit sequence as the second argument to divmod() - would seriously break backwards compatibility. Making divmod() - check its second argument for being a sequence is deemed to be too - ugly to contemplate. And in the case where one *does* have a - sequence that is computed other-where, it is easy enough to write - divmod(x, *divs) instead. +Requiring an explicit sequence as the second argument to ``divmod()`` +would seriously break backwards compatibility. Making ``divmod()`` +check its second argument for being a sequence is deemed to be too +ugly to contemplate. And in the case where one *does* have a +sequence that is computed other-where, it is easy enough to write +``divmod(x, *divs)`` instead. - Requiring at least one divisor, i.e rejecting divmod(x), has been - considered, but no good reason to do so has come to mind, and is - thus allowed in the name of generality. +Requiring at least one divisor, i.e rejecting ``divmod(x)``, has been +considered, but no good reason to do so has come to mind, and is +thus allowed in the name of generality. - Calling divmod() with no divisors should still return a tuple (of - one element). Code that calls divmod() 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 *knows* it is calling divmod() with no divisors is considered - to be too silly to warrant a special case. +Calling ``divmod()`` with no divisors should still return a tuple (of +one element). Code that calls ``divmod()`` 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 *knows* it is calling ``divmod()`` with no divisors is considered +to be too silly to warrant a special case. - 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. +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. - The inverse operation: +The inverse operation:: - def inverse_divmod(seq, *factors): - product = seq[0] - for x,y in zip(factors, seq[1:]): - product = product * x + y - return product + def inverse_divmod(seq, *factors): + product = seq[0] + for x, y in zip(factors, seq[1:]): + product = product * x + y + return product - could also be useful. However, writing +could also be useful. However, writing:: - seconds = (((((w * 7) + d) * 24 + h) * 60 + m) * 60 + s) + seconds = (((((w * 7) + d) * 24 + h) * 60 + m) * 60 + s) - 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. +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. - Calling divmod("spam") 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 divmod() would - work or not, and thus it seems silly to forbid it. +Calling ``divmod("spam")`` 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 ``divmod()`` would +work or not, and thus it seems silly to forbid it. Backwards Compatibility +======================= - Any module that replaces the divmod() function in the __builtin__ - module, may cause other modules using the new syntax to break. It - is expected that this is very uncommon. +Any module that replaces the ``divmod()`` function in the ``__builtin__`` +module, may cause other modules using the new syntax to break. It +is expected that this is very uncommon. - Code that expects a TypeError exception when calling divmod() with - anything but two arguments will break. This is also expected to - be very uncommon. +Code that expects a ``TypeError`` exception when calling ``divmod()`` with +anything but two arguments will break. This is also expected to +be very uncommon. - No other issues regarding backwards compatibility are known. +No other issues regarding backwards compatibility are known. Reference Implementation +======================== - Not finished yet, but it seems a rather straightforward - new implementation of the function builtin_divmod() in - Python/bltinmodule.c +Not finished yet, but it seems a rather straightforward +new implementation of the function ``builtin_divmod()`` in +``Python/bltinmodule.c``. + + +References +========== + +.. [1] Raymond Hettinger, "Propose rejection of PEP 303 -- Extend divmod() for + Multiple Divisors" http://mail.python.org/pipermail/python-dev/2003-January/032492.html Copyright +========= - This document has been placed in the public domain. +This document has been placed in the public domain. - -Local Variables: -mode: indented-text -indent-tabs-mode: nil -sentence-end-double-space: t -fill-column: 70 -End: + +.. + Local Variables: + mode: indented-text + indent-tabs-mode: nil + sentence-end-double-space: t + fill-column: 70 + End: