skip to content

What invariant ties Python's // and % together, and what does divmod() return?

level: middleimportance: should knowfreq 44%

answer

  1. One identity defines the pair
  2. Rebuild the dividend from both results
  3. Quotient times divisor, plus what is left
  4. A single builtin returns both halves

basics

~20 s

Python guarantees a == (a // b) * b + a % b for a non-zero divisor, so the remainder is fully determined by the floored quotient. divmod(a, b) returns both as one tuple, (a // b, a % b).

solid answer

~40 s

For any numbers with a non-zero divisor Python keeps `a == (a // b) * b + a % b`, so `%` is not an independent operation - fixing the quotient by flooring fixes the remainder. `divmod(a, b)` returns the pair `(a // b, a % b)` as a tuple in one call, which is both clearer and cheaper than computing the two separately, and it is the idiomatic way to peel units off a total: `hours, rest = divmod(seconds, 3600)`. On ints the identity is exact; on floats it holds only up to rounding error. With a zero divisor there is no meaningful pair, so `//`, `%` and `divmod` all raise `ZeroDivisionError`. Custom numeric types plug in through `__floordiv__`, `__mod__` and `__divmod__`.

code

python · 4 lines
python
seconds = 9_045
hours, rest = divmod(seconds, 3600)
minutes, secs = divmod(rest, 60)
print(f"{hours:02d}:{minutes:02d}:{secs:02d}")  # 02:30:45

go deeper

for a junior

Recall that divmod(a, b) hands back the quotient and the remainder as a two-item tuple you can unpack, and that dividing by zero raises rather than returning anything.

for a middle

Derive the remainder from the floored quotient using the identity rather than reciting values, and show a real use of divmod such as splitting seconds into hours, minutes and seconds.

for a senior

Point out the boundaries in production code: floats satisfy the identity only up to rounding, and a divisor arriving from configuration or data needs validating before it reaches //, % or divmod.

for a principal

When defining a numeric type for the codebase, treat the reconstruction identity as part of its published contract, implement __divmod__ as the single source of truth, and cover it with a property-style test.

## One identity, and everything follows Python's division operators are defined as a pair, not separately. For numbers `a` and `b` with `b != 0` the language guarantees ``` a == (a // b) * b + a % b ``` Read it as a reconstruction rule: multiply the quotient back by the divisor, add the remainder, and you must land exactly on the dividend. This is why you only ever need to remember **one** decision - that `//` floors the exact quotient toward negative infinity - because the remainder is then arithmetically forced. `-7 // 2` is -4, so `-7 % 2` has no choice but to be `-7 - (-8)`, which is 1. The identity also pins two secondary facts that are worth stating in an interview: the remainder's magnitude is always strictly less than the divisor's, and the remainder shares the divisor's sign (or is zero). ## divmod: both halves, one call `divmod(a, b)` returns the tuple `(a // b, a % b)`. It is a builtin, it unpacks naturally, and it computes both halves in a single operation rather than dividing twice: ```python full, leftover = divmod(1_000, 384) # (2, 232) ``` Three reasons to prefer it over writing `a // b` and `a % b` next to each other. It states the intent - you want to split a total into whole units plus a remainder. It cannot drift, because the two values are guaranteed to come from the same division. And it is the canonical shape for cascading unit conversions, where each remainder feeds the next split: ```python hours, rest = divmod(seconds, 3600) minutes, secs = divmod(rest, 60) ``` The same shape covers pagination (whole pages plus a partial one), pretty-printing byte counts, and converting a flat index into row and column coordinates on a grid. ## Types and floats On two ints, `divmod` returns a tuple of two ints and the identity is exact - Python's ints are unbounded, so nothing is lost. On floats it returns a tuple of two floats: `divmod(7.5, 2)` is `(3.0, 1.5)`. Note the quotient is a float even though its value is whole, because the operation promotes to float. For floats the identity is only **approximately** true. `a // b` is computed as the floor of the true quotient, then the remainder is derived, and each step rounds to the nearest representable binary64 value. When the operands differ enormously in magnitude the error in `%` can be a significant fraction of the divisor. That inaccuracy - not the sign convention alone - is why the standard library offers `math.fmod` as the recommended remainder for floats, while `%` is the right choice for integers. ## The zero divisor There is no pair to return when `b` is zero, and Python does not invent one. `a // 0`, `a % 0` and `divmod(a, 0)` all raise `ZeroDivisionError`, for floats as well as ints - `7.0 % 0.0` raises rather than producing a NaN the way raw IEEE-754 hardware semantics would. Any divisor that can arrive from configuration, a request parameter or computed data needs an explicit guard; catching `ZeroDivisionError` after the fact usually means the surrounding computation was already meaningless. ## Implementing it on your own type None of this is hardwired into the operators. `a // b` dispatches to `type(a).__floordiv__`, falling back to `type(b).__rfloordiv__` when the left operand does not know the right type; `a % b` dispatches to `__mod__`; and `divmod(a, b)` dispatches to `__divmod__`. If you define a numeric type - a fixed-point quantity, a unit-carrying measure, a modular integer - the contract users will assume is precisely the identity above. Define `__divmod__` and derive the other two from it, or define all three and test the reconstruction rule directly; a type where `(a // b) * b + a % b` misses `a` will surprise every reader. ## What interviewers are actually checking The identity is a compact way to test whether a candidate understands the operators as a system rather than as two memorised behaviours. A strong answer states the rule, uses it to *derive* `-7 % 2` instead of reciting it, mentions `divmod` as the single-call form and one real use such as unit splitting, and notes the two boundaries: floats satisfy the rule only up to rounding, and a zero divisor raises rather than returning anything.

  • Why does the identity a == (a // b) * b + a % b hold only approximately for floats?
    Each step rounds to the nearest binary64 value. The floored quotient is computed and the remainder derived from it, and both roundings introduce error, so reconstructing `a` can miss by an ulp or more. When the operands differ hugely in magnitude the error in `%` can be a noticeable fraction of the divisor, which is why the standard library recommends `math.fmod` for float remainders and `%` for integers.
  • What happens when the divisor passed to divmod() is zero?
    `divmod(a, 0)` raises `ZeroDivisionError`, exactly as `a // 0` and `a % 0` do, and this applies to floats too - `divmod(7.0, 0.0)` raises rather than producing NaN or infinity. There is no pair that satisfies the reconstruction identity, so Python refuses to invent one. Divisors that come from configuration or data should be validated before use rather than handled by catching the exception.
  • Which dunder methods must a custom numeric type implement to support //, % and divmod()?
    `__floordiv__` and `__rfloordiv__` for `//`, `__mod__` and `__rmod__` for `%`, and `__divmod__` and `__rdivmod__` for the builtin. The reflected variants let your type cooperate when it appears on the right of an operand that does not know it. The contract users assume is the reconstruction identity, so implement `__divmod__` once and derive the others, then assert the identity in a test.

saying these in an interview costs you the question

  • Treats % as independent of // rather than derived from it
  • Says divmod returns a list or a dict
  • Expects divmod on floats to return ints
  • Assumes the identity is exact for floats
  • Expects divmod(a, 0) to return a sentinel instead of raising

context