Python: why does `random.randint(a, b)` return a range inclusive of `b`?

Question:

It has always seemed strange to me that `random.randint(a, b)` would return an integer in the range `[a, b]`, instead of `[a, b-1]` like `range(...)`.

Is there any reason for this apparent inconsistency?

I don’t think there’s a reason for that. But at least it’s documented.

I guess `random.randint` was just the first attempt at implementing this feature. It seems that the Python developers also felt that this was a problem, which is why in v1.5.2 they added another method randrange with more standard parameters:

``````random.randrange([start], stop[, step])
``````

Return a randomly selected element from range(start, stop, step). This is equivalent to choice(range(start, stop, step)), but doesnâ€™t actually build a range object.

You can use `randrange` instead of `randint` to avoid surprising people.

On the other hand, in many situations where the problem is phrased as ‘choose a random number between 1 and 6’ it might be more natural to use `randint(1, 6)` instead of writing `randrange(1, 7)` or `randrange(min, max + 1)`.

I tried to get to the bottom of this by examining some old sources. I suspected that `randint` was implemented before Python’s long integer: meaning that if you wanted a random number that included `INT_MAX`, you would have needed to call `random.randrange(0, INT_MAX + 1)` which would have overflowed and resulted in arguments of `(0, 0)` or `(0, INT_MIN)` depending.

However, looking as far back as even the Python 1.5.2 sources, in `Lib/whrandom.py` we see:

``````#
# Get a random integer in the range [a, b] including both end points.
# (Deprecated; use randrange below.)
#
def randint(self, a, b):
return self.randrange(a, b+1)
``````

`whrandom.randint` was continued to be deprecated in 2.0, 2.1, 2.2, and 2.3; but `random.randint` was marked as deprecated in 2.1, although no longer marked as deprecated in 2.2.

Also, `random.py` from version 2.1 is the first to note in `random.randint`‘s docstring:

``````def randrange(self, start, stop=None, step=1, int=int, default=None):
"""Choose a random item from range(start, stop[, step]).

This fixes the problem with randint() which includes the
endpoint; in Python this is usually not what you want.
Do not supply the 'int' and 'default' arguments.
"""
``````

The only available source older than that is the 0.9.1 source, and as far as I can tell, `randint` was not implemented at that point.

Thus, I conclude that the reasoning for `randint` including the endpoint is known to only Guido himself at this point; given the docstring from Python 2.1, it sounds like the reason may have been a simple mistake.

This is speculation, but normal human usage of ‘give me a random number from a to b’ is inclusive. Implementing it that way sort of makes sense, given Python’s general philosophy of being a more human-readable language.

Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.