# Support multiple divisors in divmod()

**URL:** <https://discuss.python.org/t/support-multiple-divisors-in-divmod/33109>\
**Category:** Ideas\
**Created:** [September 6, 2023, 11:48am UTC](https://discuss.python.org/t/support-multiple-divisors-in-divmod/33109 "2023-09-06T11:48:16Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![storchaka](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/storchaka/32/217_2.png) [@storchaka](https://discuss.python.org/u/storchaka)\
**Post date:** [September 6, 2023, 11:48am UTC](https://discuss.python.org/t/support-multiple-divisors-in-divmod/33109/1 "2023-09-06T11:48:16Z")

</div>

What do you think about idea of supporting multiple divisors in `divmod()`?

So instead of

```auto
minutes, seconds = divmod(t, 60)
hours, minutes = divmod(minutes, 60)
days, hours = divmod(hours, 24)
weeks, days = divmod(days, 7)

```

you could write:

```auto
weeks, days, hours, minutes, seconds = divmod(t, 7, 24, 60, 60)

```

Sample implementation:

```auto
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)
        remainders.append(remainder)
    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?

---

<div class="post-metadata">

**Author:** ![erlendaasland](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/erlendaasland/32/4378_2.png) [@erlendaasland](https://discuss.python.org/u/erlendaasland)\
**Post date:** [September 6, 2023, 12:01pm UTC](https://discuss.python.org/t/support-multiple-divisors-in-divmod/33109/2 "2023-09-06T12:01:16Z")

</div>

> [@storchaka](#):
>
> 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.

IMO, the one-liner is harder to interpret than the “verbose” four-liner. With the current code, it is immediately easy to see what each line does.

I would not oppose the feature, though, so count me -0.

---

<div class="post-metadata">

**Author:** ![pf\_moore](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pf_moore/32/35_2.png) [@pf\_moore](https://discuss.python.org/u/pf_moore)\
**Post date:** [September 6, 2023, 12:22pm UTC](https://discuss.python.org/t/support-multiple-divisors-in-divmod/33109/3 "2023-09-06T12:22:17Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![Rosuav](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/rosuav/32/3429_2.png) [@Rosuav](https://discuss.python.org/u/Rosuav)\
**Post date:** [September 6, 2023, 12:24pm UTC](https://discuss.python.org/t/support-multiple-divisors-in-divmod/33109/4 "2023-09-06T12:24:44Z")

</div>

I’d agree with 7,24,60,60. Would it make sense for that to be a tuple rather than simply additional arguments?

```auto
weeks, days, hours, minutes, seconds = divmod(t, (7, 24, 60, 60))

```

---

<div class="post-metadata">

**Author:** ![cdce8p](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/cdce8p/32/3575_2.png) [@cdce8p](https://discuss.python.org/u/cdce8p)\
**Post date:** [September 6, 2023, 12:36pm UTC](https://discuss.python.org/t/support-multiple-divisors-in-divmod/33109/5 "2023-09-06T12:36:10Z")

</div>

> [@storchaka](#):
>
> ```auto
> minutes, seconds = divmod(t, 60)
> hours, minutes = divmod(minutes, 60)
> days, hours = divmod(hours, 24)
> weeks, days = divmod(days, 7)
> 
> ```

Just a thought, I’ve certainly used that pattern before. Not sure though it’s worth modifing `divmod` for. Maybe a helper in the datetime module instead?

---

<div class="post-metadata">

**Author:** ![Stefan2](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/stefan2/32/18492_2.png) [@Stefan2](https://discuss.python.org/u/Stefan2)\
**Post date:** [September 6, 2023, 12:44pm UTC](https://discuss.python.org/t/support-multiple-divisors-in-divmod/33109/6 "2023-09-06T12:44:21Z")

</div>

Why the artificial discrimination against zero, with additional code? If you remove the

```python
    if not divisors:
        raise TypeError('required at least one divisor')

```

then a call like `new_divmod(5)` works perfectly fine and gives the expected result `(5,)`.

---

<div class="post-metadata">

**Author:** ![ntessore](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/ntessore/32/10786_2.png) [@ntessore](https://discuss.python.org/u/ntessore)\
**Post date:** [September 6, 2023, 1:33pm UTC](https://discuss.python.org/t/support-multiple-divisors-in-divmod/33109/7 "2023-09-06T13:33:38Z")

</div>

Naively, I would have assumed that `divmod(x, a, b, c)` means repeated application over the remainder, i.e.

```py
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.

---

<div class="post-metadata">

**Author:** ![oscarbenjamin](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/oscarbenjamin/32/1209_2.png) [@oscarbenjamin](https://discuss.python.org/u/oscarbenjamin)\
**Post date:** [September 6, 2023, 2:45pm UTC](https://discuss.python.org/t/support-multiple-divisors-in-divmod/33109/8 "2023-09-06T14:45:38Z")

</div>

> [@storchaka](#):
>
> What do you think about idea of supporting multiple divisors in `divmod()`?
> 
> So instead of
> 
> ```auto
> minutes, seconds = divmod(t, 60)
> hours, minutes = divmod(minutes, 60)
> days, hours = divmod(hours, 24)
> weeks, days = divmod(days, 7)
> 
> ```
> 
> you could write:
> 
> ```auto
> weeks, days, hours, minutes, seconds = divmod(t, 7, 24, 60, 60)
> 
> ```

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:

```auto
>>> from sympy import ring, QQ
>>> R, x = ring('x', QQ)
>>> R
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:

```auto
>>> 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.

---

<div class="post-metadata">

**Author:** ![oscarbenjamin](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/oscarbenjamin/32/1209_2.png) [@oscarbenjamin](https://discuss.python.org/u/oscarbenjamin)\
**Post date:** [September 6, 2023, 3:01pm UTC](https://discuss.python.org/t/support-multiple-divisors-in-divmod/33109/9 "2023-09-06T15:01:19Z")

</div>

> [@Rosuav](#):
>
> I’d agree with 7,24,60,60. Would it make sense for that to be a tuple rather than simply additional arguments?
> 
> ```auto
> weeks, days, hours, minutes, seconds = divmod(t, (7, 24, 60, 60))
> 
> ```

This approach can just be a change to `int. __divmod__ `. What is unclear is how `divmod` would call ` __rdivmod__ ` in this scenario: does it just call `tuple. __rdivmod__ ` (and if so what should that do)?

---

<div class="post-metadata">

**Author:** ![storchaka](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/storchaka/32/217_2.png) [@storchaka](https://discuss.python.org/u/storchaka)\
**Post date:** [September 6, 2023, 5:20pm UTC](https://discuss.python.org/t/support-multiple-divisors-in-divmod/33109/10 "2023-09-06T17:20:28Z")

</div>

> [@Rosuav](#):
>
> Would it make sense for that to be a tuple rather than simply additional arguments?

Yes, there are two ways:

1. Change `int. __divmod__ `, `float. __divmod__ `, `Decimal. __divmod__ `, `Fraction. __divmod__ `, and all third-party implementations of ` __divmod__ `. They all will contain similar boring code (but usually in C):

```auto
def int. __divmod__ (self, other):
    if type(other) is tuple:
        return new_divmod(self, *other) # new_divmod() is defined above
    # old code

```

1. Implement `tuple. __rdivmod__ `:

```auto
def tuple. __rdivmod__ (self, other):
    return new_divmod(other, *self) # new_divmod() is defined above

```

I do not see obvious advantages over changing `divmod()` directly. There is a disadvantage – it will not work with object which has ` __divmod__ ` that already supports tuple. For example – a `Mock` object.

> [@Stefan2](#):
>
> Why the artificial discrimination against zero, with additional code?

The only reason is that it will allow some errors to slip through. `divmod((x, y))` will successfully return a tuple `(x, y)`. But if ignore this, yes, 1-argument `divmod()` makes sense.

---

<div class="post-metadata">

**Author:** ![oscarbenjamin](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/oscarbenjamin/32/1209_2.png) [@oscarbenjamin](https://discuss.python.org/u/oscarbenjamin)\
**Post date:** [September 6, 2023, 8:36pm UTC](https://discuss.python.org/t/support-multiple-divisors-in-divmod/33109/11 "2023-09-06T20:36:13Z")

</div>

> [@storchaka](#):
>
> I do not see obvious advantages over changing `divmod()` directly.

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.

---

<div class="post-metadata">

**Author:** ![tim.one](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/tim.one/32/282_2.png) [@tim.one](https://discuss.python.org/u/tim.one)\
**Post date:** [September 6, 2023, 9:31pm UTC](https://discuss.python.org/t/support-multiple-divisors-in-divmod/33109/12 "2023-09-06T21:31:17Z")

</div>

> [@storchaka](#):
>
> What do you think about idea of supporting multiple divisors in `divmod()`?

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](https://reference.wolfram.com/language/ref/MixedRadix.html) 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).

---

<div class="post-metadata">

**Author:** ![vovavili](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/vovavili/32/8848_2.png) [@vovavili](https://discuss.python.org/u/vovavili)\
**Post date:** [September 7, 2023, 10:41pm UTC](https://discuss.python.org/t/support-multiple-divisors-in-divmod/33109/13 "2023-09-07T22:41:25Z")

</div>

I think this would be a small neat quality-of-life adjustment for situations where you have to work with time data, I don’t see any downside. +1

---

<div class="post-metadata">

**Author:** ![NeilGirdhar](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/neilgirdhar/32/5776_2.png) [@NeilGirdhar](https://discuss.python.org/u/NeilGirdhar)\
**Post date:** [September 8, 2023, 4:08pm UTC](https://discuss.python.org/t/support-multiple-divisors-in-divmod/33109/14 "2023-09-08T16:08:09Z")

</div>

Just a thought, but you could support an infinite iterable of divisors:

```python
def new_divmod(dividend: int,
               divisors: Iterable[int]
               ) -> tuple[int, tuple[int, ...]]:
    remainders = []
    for divisor in divisors:
        if dividend == 0:
            break
        dividend, remainder = old_divmod(dividend, divisor)
        remainders.append(remainder)
    return (dividend, tuple(remainders))

```

You would have to switch to little-endian, but I think that’s more logical to me (since it puts the b^i digit in position i of the output).

This could help when doing a base conversion:

```python
x = 3492
base = 11
digits = new_divmod(x, itertools.repeat(base)) # (5, 9, 6, 2)

```

---

<div class="post-metadata">

**Author:** ![Stefan2](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/stefan2/32/18492_2.png) [@Stefan2](https://discuss.python.org/u/Stefan2)\
**Post date:** [September 8, 2023, 4:15pm UTC](https://discuss.python.org/t/support-multiple-divisors-in-divmod/33109/15 "2023-09-08T16:15:04Z")

</div>

@NeilGirdhar With an infinite iterable, that’ll never return…

---

<div class="post-metadata">

**Author:** ![Rosuav](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/rosuav/32/3429_2.png) [@Rosuav](https://discuss.python.org/u/Rosuav)\
**Post date:** [September 8, 2023, 4:18pm UTC](https://discuss.python.org/t/support-multiple-divisors-in-divmod/33109/16 "2023-09-08T16:18:23Z")

</div>

> [@Stefan2](#):
>
> With an infinite iterable, that’ll never return…

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.

---

<div class="post-metadata">

**Author:** ![Stefan2](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/stefan2/32/18492_2.png) [@Stefan2](https://discuss.python.org/u/Stefan2)\
**Post date:** [September 8, 2023, 4:32pm UTC](https://discuss.python.org/t/support-multiple-divisors-in-divmod/33109/17 "2023-09-08T16:32:39Z")

</div>

Ah, embarrassing. I’m in bad shape and didn’t read/test it properly. Sorry.

But…

> [@Rosuav](#):
>
> With any finite integer, this representation will itself be finite.

Not with `-1`, for example.

---

<div class="post-metadata">

**Author:** ![Rosuav](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/rosuav/32/3429_2.png) [@Rosuav](https://discuss.python.org/u/Rosuav)\
**Post date:** [September 8, 2023, 4:35pm UTC](https://discuss.python.org/t/support-multiple-divisors-in-divmod/33109/18 "2023-09-08T16:35:09Z")

</div>

> [@Stefan2](#):
>
> Not with `-1`, for example.

Ah true. I’m used to doing “convert to decimal” as an unsigned operation (so if you get handed a negative number, store a hyphen and negate the value).

---

<div class="post-metadata">

**Author:** ![Stefan2](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/stefan2/32/18492_2.png) [@Stefan2](https://discuss.python.org/u/Stefan2)\
**Post date:** [September 8, 2023, 4:39pm UTC](https://discuss.python.org/t/support-multiple-divisors-in-divmod/33109/19 "2023-09-08T16:39:09Z")

</div>

Yes, I’d say it would be the fault of the caller if they did that.

---

<div class="post-metadata">

**Author:** ![RonnyPfannschmidt](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/ronnypfannschmidt/32/1714_2.png) [@RonnyPfannschmidt](https://discuss.python.org/u/RonnyPfannschmidt)\
**Post date:** [September 11, 2023, 9:09am UTC](https://discuss.python.org/t/support-multiple-divisors-in-divmod/33109/20 "2023-09-11T09:09:58Z")

</div>

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

[Next page](https://discuss.python.org/t/support-multiple-divisors-in-divmod/33109.md?page=2)
