def new_divmod(dividend, *divisors):
if not divisors:
raise TypeError('required at least one divisor')
remainders = 
for divisor in reversed(divisors):
dividend, remainder = old_divmod(dividend, divisor)
return (dividend, *remainders[::-1])
I am not sure about this idea. There are not so much use cases for it. On other hand, in these rare cases when you need to write similar code, the possibility to express it in one line would be nice.
It is also not clear which order of divisors is most natural: divmod(t, 7, 24, 60, 60) or divmod(t, 60, 60, 24, 7)? Big-endian or little-endian?
I could have sworn this already existed. I can’t work out what gave me that impression, though.
It’s basically mixed-base decomposition of a number into “digits”, which is something I’ve needed occasionally, but not particularly frequently (decomposing times is the obvious example). I agree that the one-line version is a bit tricky to read, mainly because of the question of which order the divisors go in - I’m somewhat in favour of 7,24,60,60 over 60,60,24,7, but it’s not a strong preference.
I’m assuming there’s a (small) performance benefit to doing the whole thing in one call, although I doubt that would matter often enough to care.
I think I’m probably +0. It’s not a big deal, but it feels like a minor quality of life improvement.
Naively, I would have assumed that divmod(x, a, b, c) means repeated application over the remainder, i.e.
t = 12345
divmod(t, 3600, 60) == (3, 25, 45)
So the divmod(t, 7, 24, 60, 60) endianness looks more natural to me, and I would find it convenient that the function not only does the repeat application, but performs the “inner multiplication” of the argument for me.
I wonder how well this idea generalises to other cases where divmod is used. Most commonly divmod is used with integers but it can be defined for any type via __divmod__. In SymPy (and other systems) this is used for various generalisations of the idea of Euclidean division for integers for example Euclidean division of polynomials:
>>> from sympy import ring, QQ
>>> R, x = ring('x', QQ)
Polynomial ring in x over QQ with lex order
>>> divmod(x**2 - 1, x + 2)
(x - 2, 3)
For nonnegative integers the definition of Euclidean division is that if q, r = divmod(a, b) then a = q*b + r and then the condition 0 <= r < b is sufficient to uniquely define q and r. For univariate polynomials over a field the same definition applies except that the condition is changed to deg(r) < deg(b).
The further generalisation of this concept to multivariate polynomials allows the notion of dividing by a set of polynomials:
>>> R, x, y, z = ring('x, y, z', QQ)
>>> a = x**2*y + z**3 - 1
>>> b1 = y - 3
>>> b2 = z**2 - y
>>> a.div([b1, b2])
([x**2, 0], 3*x**2 + z**3 - 1)
Here division of a by b1, b2, … returns q1, q2, … and a remainder r such that a = b1*q1 + b2*q2 + ... + r. In general this is not necessarily uniquely defined but if the divisors b1, b2, … are a reduced Groebner basis with respect to some monomial ordering then requiring that the leading monomial of r be less than the leading monomials of all of the divisors (r is reduced wrt to the basis) makes the result unique.
I don’t think that the algorithm shown for new_divmod(a, b1, b2, ...) would compute this correctly though.
Ideally anything here would be customisable via __(r)divmod__ which would not be the case if the divmod function itself hard-codes a particular interpretation of the operation. It is not clear that the proposed generalisation of divmod is always applicable.
I think it doesn’t belong as a complication of divmod’s currently clean behavior.
Mixed radix conversions have builtin operator syntax in the APL language (look in APL docs for “encode” and “decode”), and in Mathematica are supplied by a MixedRadix gimmick. I recommend the Mathematica docs because they give examples of various uses.
Note that mixed radix conversions can work in both directions, and the change to divmod would cover only the “to mixed radix” case. The “from mixed radix” direction would be left unaddressed. So APL and Mathematica use a vector of bases, which can be used as-is to compute conversions in either direction (it’s the operation name that changes).
As long as it’s not an infinite sequence of 1, eventually the number will be all the way in the remainder. As a simple example, imagine dividing a large (but finite) number by 10 repeatedly - the remainders at each step are the digits in the decimal representation of that number. With any finite integer, this representation will itself be finite.
given that timedelta already has a structured way of splitting its total seconds,
i strongly question this “overpowered utility” that turns a series of clearly related expressions into a parameter with a magical meaning one will always have to re-read in the docs