Restify PEP 303 (#142)
This commit is contained in:
parent
61dcc6ef2d
commit
84de20b55d
282
pep-0303.txt
282
pep-0303.txt
|
@ -5,192 +5,210 @@ Last-Modified: $Date$
|
||||||
Author: Thomas Bellman <bellman+pep-divmod@lysator.liu.se>
|
Author: Thomas Bellman <bellman+pep-divmod@lysator.liu.se>
|
||||||
Status: Rejected
|
Status: Rejected
|
||||||
Type: Standards Track
|
Type: Standards Track
|
||||||
Content-Type: text/plain
|
Content-Type: text/x-rst
|
||||||
Created: 31-Dec-2002
|
Created: 31-Dec-2002
|
||||||
Python-Version: 2.3
|
Python-Version: 2.3
|
||||||
Post-History:
|
Post-History:
|
||||||
|
|
||||||
|
|
||||||
Abstract
|
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
|
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
|
Specification
|
||||||
|
=============
|
||||||
|
|
||||||
The built-in divmod() function would be changed to accept multiple
|
The built-in ``divmod()`` function would be changed to accept multiple
|
||||||
divisors, changing its signature from divmod(dividend, divisor) to
|
divisors, changing its signature from ``divmod(dividend, divisor)`` to
|
||||||
divmod(dividend, *divisors). The dividend is divided by the last
|
``divmod(dividend, divisors)``. The dividend is divided by the last
|
||||||
divisor, giving a quotient and a remainder. The quotient is then
|
divisor, giving a quotient and a remainder. The quotient is then
|
||||||
divided by the second to last divisor, giving a new quotient and
|
divided by the second to last divisor, giving a new quotient and
|
||||||
remainder. This is repeated until all divisors have been used,
|
remainder. This is repeated until all divisors have been used,
|
||||||
and divmod() then returns a tuple consisting of the quotient from
|
and ``divmod()`` then returns a tuple consisting of the quotient from
|
||||||
the last step, and the remainders from all the steps.
|
the last step, and the remainders from all the steps.
|
||||||
|
|
||||||
A Python implementation of the new divmod() behaviour could look
|
A Python implementation of the new ``divmod()`` behaviour could look
|
||||||
like:
|
like::
|
||||||
|
|
||||||
def divmod(dividend, *divisors):
|
def divmod(dividend, *divisors):
|
||||||
modulos = ()
|
modulos = ()
|
||||||
q = dividend
|
q = dividend
|
||||||
while divisors:
|
while divisors:
|
||||||
q,r = q.__divmod__(divisors[-1])
|
q, r = q.__divmod__(divisors[-1])
|
||||||
modulos = (r,) + modulos
|
modulos = (r,) + modulos
|
||||||
divisors = divisors[:-1]
|
divisors = divisors[:-1]
|
||||||
return (q,) + modulos
|
return (q,) + modulos
|
||||||
|
|
||||||
|
|
||||||
Motivation
|
Motivation
|
||||||
|
==========
|
||||||
|
|
||||||
Occasionally one wants to perform a chain of divmod() operations,
|
Occasionally one wants to perform a chain of ``divmod()`` operations,
|
||||||
calling divmod() on the quotient from the previous step, with
|
calling ``divmod()`` on the quotient from the previous step, with
|
||||||
varying divisors. The most common case is probably converting a
|
varying divisors. The most common case is probably converting a
|
||||||
number of seconds into weeks, days, hours, minutes and seconds.
|
number of seconds into weeks, days, hours, minutes and seconds.
|
||||||
This would today be written as:
|
This would today be written as::
|
||||||
|
|
||||||
def secs_to_wdhms(seconds):
|
def secs_to_wdhms(seconds):
|
||||||
m,s = divmod(seconds, 60)
|
m, s = divmod(seconds, 60)
|
||||||
h,m = divmod(m, 60)
|
h, m = divmod(m, 60)
|
||||||
d,h = divmod(h, 24)
|
d, h = divmod(h, 24)
|
||||||
w,d = divmod(d, 7)
|
w, d = divmod(d, 7)
|
||||||
return (w,d,h,m,s)
|
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,
|
If instead the ``divmod()`` built-in is changed according the proposal,
|
||||||
the code for converting seconds to weeks, days, hours, minutes and
|
the code for converting seconds to weeks, days, hours, minutes and
|
||||||
seconds then become
|
seconds then become::
|
||||||
|
|
||||||
def secs_to_wdhms(seconds):
|
def secs_to_wdhms(seconds):
|
||||||
w,d,h,m,s = divmod(seconds, 7, 24, 60, 60)
|
w, d, h, m, s = divmod(seconds, 7, 24, 60, 60)
|
||||||
return (w,d,h,m,s)
|
return (w, d, h, m, s)
|
||||||
|
|
||||||
which is easier to type, easier to type correctly, and easier to
|
which is easier to type, easier to type correctly, and easier to
|
||||||
read.
|
read.
|
||||||
|
|
||||||
Other applications are:
|
Other applications are:
|
||||||
|
|
||||||
- Astronomical angles (declination is measured in degrees, minutes
|
- Astronomical angles (declination is measured in degrees, minutes
|
||||||
and seconds, right ascension is measured in hours, minutes and
|
and seconds, right ascension is measured in hours, minutes and
|
||||||
seconds).
|
seconds).
|
||||||
- Old British currency (1 pound = 20 shilling, 1 shilling = 12 pence)
|
- Old British currency (1 pound = 20 shilling, 1 shilling = 12 pence)
|
||||||
- Anglo-Saxon length units: 1 mile = 1760 yards, 1 yard = 3 feet,
|
- Anglo-Saxon length units: 1 mile = 1760 yards, 1 yard = 3 feet,
|
||||||
1 foot = 12 inches.
|
1 foot = 12 inches.
|
||||||
- Anglo-Saxon weight units: 1 long ton = 160 stone, 1 stone = 14
|
- Anglo-Saxon weight units: 1 long ton = 160 stone, 1 stone = 14
|
||||||
pounds, 1 pound = 16 ounce, 1 ounce = 16 dram
|
pounds, 1 pound = 16 ounce, 1 ounce = 16 dram
|
||||||
- British volumes: 1 gallon = 4 quart, 1 quart = 2 pint, 1 pint
|
- British volumes: 1 gallon = 4 quart, 1 quart = 2 pint, 1 pint
|
||||||
= 20 fluid ounces
|
= 20 fluid ounces
|
||||||
|
|
||||||
|
|
||||||
Rationale
|
Rationale
|
||||||
|
=========
|
||||||
|
|
||||||
The idea comes from APL, which has an operator that does this. (I
|
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
|
don't remember what the operator looks like, and it would probably
|
||||||
be impossible to render in ASCII anyway.)
|
be impossible to render in ASCII anyway.)
|
||||||
|
|
||||||
The APL operator takes a list as its second operand, while this
|
The APL operator takes a list as its second operand, while this
|
||||||
PEP proposes that each divisor should be a separate argument to
|
PEP proposes that each divisor should be a separate argument to
|
||||||
the divmod() function. This is mainly because it is expected that
|
the ``divmod()`` function. This is mainly because it is expected that
|
||||||
the most common uses will have the divisors as constants right in
|
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
|
the call (as the 7, 24, 60, 60 above), and adding a set of
|
||||||
parentheses or brackets would just clutter the call.
|
parentheses or brackets would just clutter the call.
|
||||||
|
|
||||||
Requiring an explicit sequence as the second argument to divmod()
|
Requiring an explicit sequence as the second argument to ``divmod()``
|
||||||
would seriously break backwards compatibility. Making divmod()
|
would seriously break backwards compatibility. Making ``divmod()``
|
||||||
check its second argument for being a sequence is deemed to be too
|
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
|
ugly to contemplate. And in the case where one *does* have a
|
||||||
sequence that is computed other-where, it is easy enough to write
|
sequence that is computed other-where, it is easy enough to write
|
||||||
divmod(x, *divs) instead.
|
``divmod(x, *divs)`` instead.
|
||||||
|
|
||||||
Requiring at least one divisor, i.e rejecting divmod(x), has been
|
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
|
considered, but no good reason to do so has come to mind, and is
|
||||||
thus allowed in the name of generality.
|
thus allowed in the name of generality.
|
||||||
|
|
||||||
Calling divmod() with no divisors should still return a tuple (of
|
Calling ``divmod()`` with no divisors should still return a tuple (of
|
||||||
one element). Code that calls divmod() with a varying number of
|
one element). Code that calls ``divmod()`` with a varying number of
|
||||||
divisors, and thus gets a return value with an "unknown" number of
|
divisors, and thus gets a return value with an "unknown" number of
|
||||||
elements, would otherwise have to special case that case. Code
|
elements, would otherwise have to special case that case. Code
|
||||||
that *knows* it is calling divmod() with no divisors is considered
|
that *knows* it is calling ``divmod()`` with no divisors is considered
|
||||||
to be too silly to warrant a special case.
|
to be too silly to warrant a special case.
|
||||||
|
|
||||||
Processing the divisors in the other direction, i.e dividing with
|
Processing the divisors in the other direction, i.e dividing with
|
||||||
the first divisor first, instead of dividing with the last divisor
|
the first divisor first, instead of dividing with the last divisor
|
||||||
first, has been considered. However, the result comes with the
|
first, has been considered. However, the result comes with the
|
||||||
most significant part first and the least significant part last
|
most significant part first and the least significant part last
|
||||||
(think of the chained divmod as a way of splitting a number into
|
(think of the chained divmod as a way of splitting a number into
|
||||||
"digits", with varying weights), and it is reasonable to specify
|
"digits", with varying weights), and it is reasonable to specify
|
||||||
the divisors (weights) in the same order as the result.
|
the divisors (weights) in the same order as the result.
|
||||||
|
|
||||||
The inverse operation:
|
The inverse operation::
|
||||||
|
|
||||||
def inverse_divmod(seq, *factors):
|
def inverse_divmod(seq, *factors):
|
||||||
product = seq[0]
|
product = seq[0]
|
||||||
for x,y in zip(factors, seq[1:]):
|
for x, y in zip(factors, seq[1:]):
|
||||||
product = product * x + y
|
product = product * x + y
|
||||||
return product
|
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
|
is less cumbersome both to write and to read than the chained
|
||||||
divmods. It is therefore deemed to be less important, and its
|
divmods. It is therefore deemed to be less important, and its
|
||||||
introduction can be deferred to its own PEP. Also, such a
|
introduction can be deferred to its own PEP. Also, such a
|
||||||
function needs a good name, and the PEP author has not managed to
|
function needs a good name, and the PEP author has not managed to
|
||||||
come up with one yet.
|
come up with one yet.
|
||||||
|
|
||||||
Calling divmod("spam") does not raise an error, despite strings
|
Calling ``divmod("spam")`` does not raise an error, despite strings
|
||||||
supporting neither division nor modulo. However, unless we know
|
supporting neither division nor modulo. However, unless we know
|
||||||
the other object too, we can't determine whether divmod() would
|
the other object too, we can't determine whether ``divmod()`` would
|
||||||
work or not, and thus it seems silly to forbid it.
|
work or not, and thus it seems silly to forbid it.
|
||||||
|
|
||||||
|
|
||||||
Backwards Compatibility
|
Backwards Compatibility
|
||||||
|
=======================
|
||||||
|
|
||||||
Any module that replaces the divmod() function in the __builtin__
|
Any module that replaces the ``divmod()`` function in the ``__builtin__``
|
||||||
module, may cause other modules using the new syntax to break. It
|
module, may cause other modules using the new syntax to break. It
|
||||||
is expected that this is very uncommon.
|
is expected that this is very uncommon.
|
||||||
|
|
||||||
Code that expects a TypeError exception when calling divmod() with
|
Code that expects a ``TypeError`` exception when calling ``divmod()`` with
|
||||||
anything but two arguments will break. This is also expected to
|
anything but two arguments will break. This is also expected to
|
||||||
be very uncommon.
|
be very uncommon.
|
||||||
|
|
||||||
No other issues regarding backwards compatibility are known.
|
No other issues regarding backwards compatibility are known.
|
||||||
|
|
||||||
|
|
||||||
Reference Implementation
|
Reference Implementation
|
||||||
|
========================
|
||||||
|
|
||||||
Not finished yet, but it seems a rather straightforward
|
Not finished yet, but it seems a rather straightforward
|
||||||
new implementation of the function builtin_divmod() in
|
new implementation of the function ``builtin_divmod()`` in
|
||||||
Python/bltinmodule.c
|
``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
|
Copyright
|
||||||
|
=========
|
||||||
|
|
||||||
This document has been placed in the public domain.
|
This document has been placed in the public domain.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Local Variables:
|
..
|
||||||
mode: indented-text
|
Local Variables:
|
||||||
indent-tabs-mode: nil
|
mode: indented-text
|
||||||
sentence-end-double-space: t
|
indent-tabs-mode: nil
|
||||||
fill-column: 70
|
sentence-end-double-space: t
|
||||||
End:
|
fill-column: 70
|
||||||
|
End:
|
||||||
|
|
Loading…
Reference in New Issue