@@ -5,192 +5,210 @@ Last-Modified: $Date$
5
5
Author: Thomas Bellman <bellman+pep-divmod@lysator.liu.se>
6
6
Status: Rejected
7
7
Type: Standards Track
8
- Content-Type: text/plain
8
+ Content-Type: text/x-rst
9
9
Created: 31-Dec-2002
10
10
Python-Version: 2.3
11
11
Post-History:
12
12
13
13
14
14
Abstract
15
+ ========
16
+
17
+ This PEP describes an extension to the built-in ``divmod()`` function,
18
+ allowing it to take multiple divisors, chaining several calls to
19
+ ``divmod()`` into one.
15
20
16
- This PEP describes an extension to the built-in divmod() function,
17
- allowing it to take multiple divisors, chaining several calls to
18
- divmod() into one.
19
21
20
22
Pronouncement
23
+ =============
24
+
25
+ This PEP is rejected. Most uses for chained ``divmod()`` involve a
26
+ constant modulus (in radix conversions for example) and are more
27
+ properly coded as a loop. The example of splitting seconds
28
+ into days/hours/minutes/seconds does not generalize to months
29
+ and years; rather, the whole use case is handled more flexibly and
30
+ robustly by date and time modules. The other use cases mentioned
31
+ in the PEP are somewhat rare in real code. The proposal is also
32
+ problematic in terms of clarity and obviousness. In the examples,
33
+ it is not immediately clear that the argument order is correct or
34
+ that the target tuple is of the right length. Users from other
35
+ languages are more likely to understand the standard two argument
36
+ form without having to re-read the documentation. See python-dev
37
+ discussion on 17 June 2005 [1]_.
21
38
22
- This PEP is rejected. Most uses for chained divmod() involve a
23
- constant modulus (in radix conversions for example) and are more
24
8000
- properly coded as a loop. The example of splitting seconds
25
- into days/hours/minutes/seconds does not generalize to months
26
- and years; rather, the whole use case is handled more flexibly and
27
- robustly by date and time modules. The other use cases mentioned
28
- in the PEP are somewhat rare in real code. The proposal is also
29
- problematic in terms of clarity and obviousness. In the examples,
30
- it is not immediately clear that the argument order is correct or
31
- that the target tuple is of the right length. Users from other
32
- languages are more likely to understand the standard two argument
33
- form without having to re-read the documentation. See python-dev
34
- discussion on 17 June 2005.
35
39
36
40
Specification
37
-
38
- The built-in divmod() function would be changed to accept multiple
39
- divisors, changing its signature from divmod(dividend, divisor) to
40
- divmod(dividend, *divisors). The dividend is divided by the last
41
- divisor, giving a quotient and a remainder. The quotient is then
42
- divided by the second to last divisor, giving a new quotient and
43
- remainder. This is repeated until all divisors have been used,
44
- and divmod() then returns a tuple consisting of the quotient from
45
- the last step, and the remainders from all the steps.
46
-
47
- A Python implementation of the new divmod() behaviour could look
48
- like:
49
-
50
- def divmod(dividend, *divisors):
51
- modulos = ()
52
- q = dividend
53
- while divisors:
54
- q,r = q.__divmod__(divisors[-1])
55
- modulos = (r,) + modulos
56
- divisors = divisors[:-1]
57
- return (q,) + modulos
41
+ =============
42
+
43
+ The built-in ``divmod()`` function would be changed to accept multiple
44
+ divisors, changing its signature from ``divmod(dividend, divisor)`` to
45
+ ``divmod(dividend, divisors)``. The dividend is divided by the last
46
+ divisor, giving a quotient and a remainder. The quotient is then
47
+ divided by the second to last divisor, giving a new quotient and
48
+ remainder. This is repeated until all divisors have been used,
49
+ and ``divmod()`` then returns a tuple consisting of the quotient from
50
+ the last step, and the remainders from all the steps.
51
+
52
+ A Python implementation of the new ``divmod()`` behaviour could look
53
+ like::
54
+
55
+ def divmod(dividend, *divisors):
56
+ modulos = ()
57
+ q = dividend
58
+ while divisors:
59
+ q, r = q.__divmod__(divisors[-1])
60
+ modulos = (r,) + modulos
61
+ divisors = divisors[:-1]
62
+ return (q,) + modulos
58
63
59
64
60
65
Motivation
66
+ ==========
61
67
62
- Occasionally one wants to perform a chain of divmod() operations,
63
- calling divmod() on the quotient from the previous step, with
64
- varying divisors. The most common case is probably converting a
65
- number of seconds into weeks, days, hours, minutes and seconds.
66
- This would today be written as:
68
+ Occasionally one wants to perform a chain of `` divmod()`` operations,
69
+ calling `` divmod()`` on the quotient from the previous step, with
70
+ varying divisors. The most common case is probably converting a
71
+ number of seconds into weeks, days, hours, minutes and seconds.
72
+ This would today be written as: :
67
73
68
- def secs_to_wdhms(seconds):
69
- m, s = divmod(seconds, 60)
70
- h, m = divmod(m, 60)
71
- d, h = divmod(h, 24)
72
- w, d = divmod(d, 7)
73
- return (w,d,h,m, s)
74
+ def secs_to_wdhms(seconds):
75
+ m, s = divmod(seconds, 60)
76
+ h, m = divmod(m, 60)
77
+ d, h = divmod(h, 24)
78
+ w, d = divmod(d, 7)
79
+ return (w, d, h, m, s)
74
80
75
- This is tedious and easy to get wrong each time you need it.
81
+ This is tedious and easy to get wrong each time you need it.
76
82
77
- If instead the divmod() built-in is changed according the proposal,
78
- the code for converting seconds to weeks, days, hours, minutes and
79
- seconds then become
83
+ If instead the `` divmod()`` built-in is changed according the proposal,
84
+ the code for converting seconds to weeks, days, hours, minutes and
85
+ seconds then become::
80
86
81
- def secs_to_wdhms(seconds):
82
- w,d,h,m, s = divmod(seconds, 7, 24, 60, 60)
83
- return (w,d,h,m, s)
87
+ def secs_to_wdhms(seconds):
88
+ w, d, h, m, s = divmod(seconds, 7, 24, 60, 60)
89
+ return (w, d, h, m, s)
84
90
85
- which is easier to type, easier to type correctly, and easier to
86
- read.
91
+ which is easier to type, easier to type correctly, and easier to
92
+ read.
87
93
88
- Other applications are:
94
+ Other applications are:
89
95
90
- - Astronomical angles (declination is measured in degrees, minutes
91
- and seconds, right ascension is measured in hours, minutes and
92
- seconds).
93
- - Old British currency (1 pound = 20 shilling, 1 shilling = 12 pence)
94
- - Anglo-Saxon length units: 1 mile = 1760 yards, 1 yard = 3 feet,
95
- 1 foot = 12 inches.
96
- - Anglo-Saxon weight units: 1 long ton = 160 stone, 1 stone = 14
97
- pounds, 1 pound = 16 ounce, 1 ounce = 16 dram
98
- - British volumes: 1 gallon = 4 quart, 1 quart = 2 pint, 1 pint
99
- = 20 fluid ounces
96
+ - Astronomical angles (declination is measured in degrees, minutes
97
+ and seconds, right ascension is measured in hours, minutes and
98
+ seconds).
99
+ - Old British currency (1 pound = 20 shilling, 1 shilling = 12 pence)
100
+ - Anglo-Saxon length units: 1 mile = 1760 yards, 1 yard = 3 feet,
101
+ 1 foot = 12 inches.
102
+ - Anglo-Saxon weight units: 1 long ton = 160 stone, 1 stone = 14
103
+ pounds, 1 pound = 16 ounce, 1 ounce = 16 dram
104
+ - British volumes: 1 gallon = 4 quart, 1 quart = 2 pint, 1 pint
105
+ = 20 fluid ounces
100
106
101
107
102
108
Rationale
103
-
104
- The idea comes from APL, which has an operator that does this. (I
105
- don't remember what the operator looks like, and it would probably
106
- be impossible to render in ASCII anyway.)
107
-
108
- The APL operator takes a list as its second operand, while this
109
- PEP proposes that each divisor should be a separate argument to
110
- the divmod() function. This is mainly because it is expected that
111
- the most common uses will have the divisors as constants right in
112
- the call (as the 7, 24, 60, 60 above), and adding a set of
113
- parentheses or brackets would just clutter the call.
114
-
115
- Requiring an explicit sequence as the second argument to divmod()
116
- would seriously break backwards compatibility. Making divmod()
117
- check its second argument for being a sequence is deemed to be too
118
- ugly to contemplate. And in the case where one *does* have a
119
- sequence that is computed other-where, it is easy enough to write
120
- divmod(x, *divs) instead.
121
-
122
- Requiring at least one divisor, i.e rejecting divmod(x), has been
123
- considered, but no good reason to do so has come to mind, and is
124
- thus allowed in the name of generality.
125
-
126
- Calling divmod() with no divisors should still return a tuple (of
127
- one element). Code that calls divmod() with a varying number of
128
- divisors, and thus gets a return value with an "unknown" number of
129
- elements, would otherwise have to special case that case. Code
130
- that *knows* it is calling divmod() with no divisors is considered
131
- to be too silly to warrant a special case.
132
-
133
- Processing the divisors in the other direction, i.e dividing with
134
- the first divisor first, instead of dividing with the last divisor
135
- first, has been considered. However, the result comes with the
136
- most significant part first and the least significant part last
137
- (think of the chained divmod as a way of splitting a number into
138
- "digits", with varying weights), and it is reasonable to specify
139
- the divisors (weights) in the same order as the result.
140
-
141
- The inverse operation:
142
-
143
- def inverse_divmod(seq, *factors):
144
- product = seq[0]
145
- for x,y in zip(factors, seq[1:]):
146
- product = product * x + y
147
- return product
148
-
149
- could also be useful. However, writing
150
-
151
- seconds = (((((w * 7) + d) * 24 + h) * 60 + m) * 60 + s)
152
-
153
- is less cumbersome both to write and to read than the chained
154
- divmods. It is therefore deemed to be less important, and its
155
- introduction can be deferred to its own PEP. Also, such a
156
- function needs a good name, and the PEP author has not managed to
157
- come up with one yet.
158
-
159
- Calling divmod("spam") does not raise an error, despite strings
160
- supporting neither division nor modulo. However, unless we know
161
- the other object too, we can't determine whether divmod() would
162
- work or not, and thus it seems silly to forbid it.
109
+ =========
110
+
111
+ The idea comes from APL, which has an operator that does this. (I
112
+ don't remember what the operator looks like, and it would probably
113
+ be impossible to render in ASCII anyway.)
114
+
115
+ The APL operator takes a list as its second operand, while this
116
+ PEP proposes that each divisor should be a separate argument to
117
+ the ``divmod()`` function. This is mainly because it is expected that
118
+ the most common uses will have the divisors as constants right in
119
+ the call (as the 7, 24, 60, 60 above), and adding a set of
120
+ parentheses or brackets would just clutter the call.
121
+
122
+ Requiring an explicit sequence as the second argument to ``divmod()``
123
+ would seriously break backwards compatibility. Making ``divmod()``
124
+ check its second argument for being a sequence is deemed to be too
125
+ ugly to contemplate. And in the case where one *does* have a
126
+ sequence that is computed other-where, it is easy enough to write
127
+ ``divmod(x, *divs)`` instead.
128
+
129
+ Requiring at least one divisor, i.e rejecting ``divmod(x)``, has been
130
+ considered, but no good reason to do so has come to mind, and is
131
+ thus allowed in the name of generality.
132
+
133
+ Calling ``divmod()`` with no divisors should still return a tuple (of
134
+ one element). Code that calls ``divmod()`` with a varying number of
135
+ divisors, and thus gets a return value with an "unknown" number of
136
+ elements, would otherwise have to special case that case. Code
137
+ that *knows* it is calling ``divmod()`` with no divisors is considered
138
+ to be too silly to warrant a special case.
139
+
140
+ Processing the divisors in the other direction, i.e dividing with
141
+ the first divisor first, instead of dividing with the last divisor
142
+ first, has been considered. However, the result comes with the
143
+ most significant part first and the least significant part last
144
+ (think of the chained divmod as a way of splitting a number into
145
+ "digits", with varying weights), and it is reasonable to specify
146
+ the divisors (weights) in the same order as the result.
147
+
148
+ The inverse operation::
149
+
150
+ def inverse_divmod(seq, *factors):
151
+ product = seq[0]
152
+ for x, y in zip(factors, seq[1:]):
153
+ product = product * x + y
154
+ return product
155
+
156
+ could also be useful. However, writing::
157
+
158
+ seconds = (((((w * 7) + d) * 24 + h) * 60 + m) * 60 + s)
159
+
160
+ is less cumbersome both to write and to read than the chained
161
+ divmods. It is therefore deemed to be less important, and its
162
+ introduction can be deferred to its own PEP. Also, such a
163
+ function needs a good name, and the PEP author has not managed to
164
+ come up with one yet.
165
+
166
+ Calling ``divmod("spam")`` does not raise an error, despite strings
167
+ supporting neither division nor modulo. However, unless we know
168
+ the other object too, we can't determine whether ``divmod()`` would
169
+ work or not, and thus it seems silly to forbid it.
163
170
164
171
165
172
Backwards Compatibility
173
+ =======================
166
174
167
- Any module that replaces the divmod() function in the __builtin__
168
- module, may cause other modules using the new syntax to break. It
169
- is expected that this is very uncommon.
175
+ Any module that replaces the `` divmod()`` function in the `` __builtin__``
176
+ module, may cause other modules using the new syntax to break. It
177
+ is expected that this is very uncommon.
170
178
171
- Code that expects a TypeError exception when calling divmod() with
172
- anything but two arguments will break. This is also expected to
173
- be very uncommon.
179
+ Code that expects a `` TypeError`` exception when calling `` divmod()`` with
180
+ anything but two arguments will break. This is also expected to
181
+ be very uncommon.
174
182
175
- No other issues regarding backwards compatibility are known.
183
+ No other issues regarding backwards compatibility are known.
176
184
177
185
178
186
Reference Implementation
187
+ ========================
179
188
180
- Not finished yet, but it seems a rather straightforward
181
- new implementation of the function builtin_divmod() in
182
- Python/bltinmodule.c
189
+ Not finished yet, but it seems a rather straightforward
190
+ new implementation of the function ``builtin_divmod()`` in
191
+ ``Python/bltinmodule.c``.
192
+
193
+
194
+ References
195
+ ==========
196
+
197
+ .. [1] Raymond Hettinger, "Propose rejection of PEP 303 -- Extend divmod() for
198
+ Multiple Divisors" http://mail.python.org/pipermail/python-dev/2003-January/032492.html
183
199
184
200
185
201
Copyright
202
+ =========
203
+
204
+ This document has been placed in the public domain.
186
205
187
- This document has been placed in the public domain.
188
206
189
207
190
-
191
- Local Variables:
192
- mode: indented-text
193
- indent-tabs-mode: nil
194
- sentence-end-double-space: t
195
- fill-column: 70
196
- End:
208
+ ..
209
+ Local Variables:
210
+ mode: indented-text
211
+ indent-tabs-mode: nil
212
+ sentence-end-double-space: t
213
+ fill-column: 70
214
+ End:
0 commit comments