Подтвердить что ты не робот

Python: почему `random.randint(a, b)` возвращает диапазон, включающий `b`?

Мне всегда казалось странным, что random.randint(a, b) вернет целое число в диапазоне [a, b] вместо [a, b-1] как range(...).

Есть ли причина для этой очевидной несогласованности?

4b9b3361

Ответ 1

Я попытался разобраться в этом, изучив некоторые старые источники. Я подозревал, что randint был реализован до длинного целого Python: это означает, что если вы хотите случайное число, включающее INT_MAX, вам нужно было бы вызвать random.randrange(0, INT_MAX + 1), который переполнился бы и привел бы к аргументам (0, 0) или (0, INT_MIN) зависит.

Однако, глядя еще в источники Python 1.5.2, в Lib/whrandom.py мы видим:

#
# 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 продолжал оставаться устаревшим в 2.0, 2.1, 2.2 и 2.3; но random.randint отмечен как устаревший в 2.1, хотя он больше не отмечен как устаревший в 2,2.

Кроме того, random.py из версии 2.1 является первым, чтобы отметить в random.randint 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.
    """

Единственный доступный источник, более старый, чем источник 0.9.1, и насколько я могу судить, randint не был реализован в этот момент.

Таким образом, я пришел к выводу, что аргументация randint, включая конечную точку, известна только самому Гвидо; с учетом docstring из Python 2.1, это звучит так, что причина могла быть простой ошибкой.

Ответ 2

Думаю, random.randint была первой попыткой реализовать эту функцию. Похоже, разработчики Python также чувствовали, что это проблема, поэтому в версии 1.5.2 они добавили еще один метод randrange с более стандартным параметры:

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

Возвращает случайно выбранный элемент из диапазона (начало, остановка, шаг). Это эквивалентно выбору (диапазон (начало, остановка, шаг)), но фактически не создает объект диапазона.

Вы можете использовать randrange вместо randint, чтобы избежать неожиданных людей.

С другой стороны, во многих ситуациях, когда проблема формулируется как "выбирать случайное число между 1 и 6", более естественно использовать randint(1, 6) вместо записи randrange(1, 7) или randrange(min, max + 1).

Ответ 3

Это предположение, но нормальное использование человеком "дать мне случайное число от a до b" включено. Реализация его таким образом имеет смысл, учитывая общую философию Питона о том, чтобы быть более понятным для человека языком.

Ответ 4

Я не думаю, что есть причина для этого. Но, по крайней мере, это задокументировано.