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
Is there any reason for this apparent inconsistency?
I don’t think there’s a reason for that. But at least it’s documented.
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)
random.py from version 2.1 is the first to note in
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.