Рандом (random) в Python — как генерировать случайные числа

Случайные числа применяются в программировании в разных случаях, например, для моделирования процессов и в видеоиграх. Для начала разберёмся, какую последовательность можно назвать случайной.

Случайной последовательностью называют набор элементов, полученных таким образом, что любой элемент их этого набора никак не связан ни с каким другим элементом. При этом в программировании обычно последовательность не является строго случайной — в ней для генерации следующего элемента используется предыдущий.

Как работают случайные числа

Полностью случайные числа генерируются истинным генератором случайных чисел (TRNG). Их можно получить, например, бросанием кубика или доставанием шаров из урны. Так как подобных устройств нет в компьютере, то в нем можно получить только "псевдослучайные" числа.

В Python, как и во всех остальных языках программирования, используется генератор псевдослучайных чисел, который выдает как будто случайные, но воспроизводимые числа.

Чтобы понять, как работают генераторы псевдослучайных чисел, рассмотрим работу одного из первых подобных генераторов. Его алгоритм работы был разработан Нейманом. В нем первое число возводят в квадрат, а потом из полученного результата берут средние цифры. Например, первое число 281, возводим его в квадрат, получаем 78961 и берем три цифры, находящиеся в середине – 896. После этого для генерации следующего числа используем 896.

Модуль random

В модуле random реализованы различные генераторы псевдослучайных чисел. Здесь присутствуют методы, с помощью которых можно получить равномерное, Гауссовское, бета и гамма распределения и другие функции. Практически все они зависят от метода random(). В Python, в качестве основного, используется генератор псевдослучайных чисел Mersenne Twister, который выдает 53-х битные вещественные числа.

👉 Как использовать: чтобы начать использовать встроенные генераторы случайных чисел, нужно сначала подключить модуль рандом:

import random

После этого можно вызывать методы модуля random:

random.randint(0, 125)

В модуле random существуют методы для генерации целых чисел, с плавающей точкой, для работы с последовательностями. Кроме этого существуют функции для управления генератором и генерации различных последовательностей. Рассмотрим основные из этих методов.

Случайные целые числа (int)

Перечислим основные функции, которые есть в модуле random для выдачи случайных целых чисел.

randint Функция randint(a, b) получает на вход два целых числа и возвращает случайное значение из диапазона [a, b] (a и b входят в этот диапазон).

import random random_number = random.randint(0, 125) print(random_number) > 113

randrange В функцию randrange(start, stop[, step]) передают три целых числа:

  • start – начало диапазона (входит в последовательность);
  • stop – конец диапазона (в последовательность не входит);
  • step – шаг генерации (если на его месте написать 0, получим ошибку "ValueError").

На выходе функция выдает случайное число в заданном диапазоне.

import random random_number = random.randrange(1, 100, 2) print(random_number) > 43

Случайные вещественные числа (float)

Перечислим функции, которые выдают вещественные числа.

random Функция random() выдает вещественные числа, в диапазоне [0.0, 1.0) (включая 0.0, но не включая 1.0).

import random random_number = random.random() print(random_number) > 0.47673250896173136

uniform Сгенерировать число с плавающей точкой можно с помощью функции uniform(a, b). При этом полученное число будет в диапазоне [a, b) или [a, b] (a входит в диапазон, а вхождение b зависит от округления).

import random random_number = random.uniform(7.3, 10.5) print(random_number) > 10.320165816501492

Случайные элементы из последовательности

В модуле random языка Python есть несколько функций, которые можно применять для работы с последовательностями.

choice С помощью функции choice(seq) можно выбрать один элемент из набора данных. В качестве единственного аргумента в функцию передаётся последовательность. Если последовательность будет пустой (то есть в ней не будет ни одного элемента), получим ошибку "IndexError".

import random seq = [10, 11, 12, 13, 14, 15] random_element = random.choice(seq) print(random_element) > 12

choices С помощью функции choices(seq [, weights, cum_weights, k]) можно выбрать 1 или несколько элементов из набора данных. weights, cum_weights и k — необязательные параметры.

  • weights — список относительных весов;
  • cum_weights — список кумулятивных (совокупных) весов, например weights [10, 5, 30, 5] эквивалентен cum_weights [10, 15, 45, 50].
  • k — длина возвращаемого списка (она может быть больше длины переданной последовательности и элементы могут дублироваться).
import random seq = [1, 2, 3, 4, 5, 6] random_elements = random.choices(seq, weights=[20, 1.1, 1, 2.1, 10, 1], k=4) print(random_elements) > [5, 1, 1, 5]

shuffle Перемешать элементы набора данных можно с помощью функции shuffle(x[, random]).

  • х — последовательность;
  • random (необязательный параметр) — задает метод вероятностных распределений. Этот параметр не рекомендуется использовать в версии Python 3.9, а в версии 3.11 его поддержка будет прекращена.

shuffle перемешивает переданную последовательность, и возвращает None.

import random seq = ["Cappuccino", "Latte", "Espresso", "Americano"] random.shuffle(seq) print(seq) > ['Espresso', 'Americano', 'Latte', 'Cappuccino']

sample Чтобы выбрать какое-то количество элементов из набора данных можно воспользоваться функцией sample(х, k).

  • х — последовательность;
  • k — количество элементов новой подпоследовательности.

На выходе получаем k уникальных случайных элементов из последовательности.

Если в исходной последовательности есть неуникальные (повторяющиеся) элементы, то каждый их них может появиться в новом списке.
import random seq = [10, 11, 12, 11, 14, 11] random_seq = random.sample(seq, 4) print(random_seq) > [10, 11, 11, 14]

Управление генератором

Генерация чисел в Python не совсем случайна и зависит от состояния генератора случайных чисел. Рассмотрим функции, с помощью которых можно управлять состоянием этого генератора.

getstate Метод getstate() модуля random возвращает объект, в котором записано текущим состояние генератора случайных чисел. Его можно использовать для восстановления состояния генератора. Эта функция не имеет параметров.

import random print(random.getstate()) > (3, (2147483648, 3570748448, 2839542888, 4273933825, 4291584237, ...

setstate Метод setstate(state) применяется для восстановления состояния генератора случайных чисел. Обычно его используют совместно с методом getstate(). В качестве параметра в функцию передается объект состояния генератора, полученный, например, с помощью функции getstate().

import random state = random.getstate() # сохраняем текущее состояние генератора random_number_1 = random.random() # получаем случайное число print(random_number_1) # > 0.42164837822065193 # первое случайное число random_number_2 = random.random() print(random_number_2) # > 0.2486825504535808 # второе случайное число random.setstate(state) # восстанавливаем состояние генератора random_number_3 = random.random() # снова генерируем число print(random_number_3) # > 0.42164837822065193 # новое число равное первому, сгенерированному с тем же состояние генератора

seed Генератору случайных чисел нужно число, основываясь на котором он сможет начать генерировать случайные значения.

Задать начальное значение можно с помощью метода seed(a=None, version=2).

  • а — начальное число, с которого начинается генерация. Этот параметр не обязательный. Если он не задан, используется текущее системное время (или доступный механизм генерации, предоставляемый ОС);
  • version — стратегия интерпретации первого аргумента. По умолчанию используется версия 2, при которой str, bytes и bytearray преобразуются в int. Версия 1 (используется для совместимости со старыми версиями Python) и в ней для str и bytes генерирует более узкий диапазон начальных значений.

Вероятностное распределение

В теории вероятностей важную роль играет понятие распределение вероятностей. Оно показывает с какой вероятность может наступить каждое из возможных событий. С его помощью можно моделировать как наступление дискретных событий (например, бросание монеты, количество телефонных разговоров за неделю, количество пассажиров в автобусе), так и непрерывных (например, длительность разговора, количество осадков за год, расход электричества за месяц).

Для наглядности рассмотрим самое распространенное нормальное распределение вероятностей. На рисунке ниже приведена кривая нормального распределения.

В модуле random существуют функции, которые позволяют использовать различные методы вероятностных распределений:

  • triangular(a, b, mode) — генерирует случайное вещественное число, находящееся в диапазоне от a до b. По умолчанию эти параметры равны: а = 0, b = 1. Третий параметр mode задает среднюю точку вероятности распределения. (подробнее про треугольное распределение тут).
  • betavariate(alpha, beta) — генерирует случайные числа соответствующие параметрам бета-распределения. Возвращаемые значения лежат в диапазоне от 0 до 1.
  • expovariate(lambd) — можно получить случайные значения, соответствующие экспоненциальному распределению. Если lambd положительное, то на выходе будут значения от 0 до +∞, а если отрицательное, то от -∞ до 0.
  • gammavariate(alpha, beta) — на выходе получаются случайные числа, соответствующие гамма распределению. Параметры alpha и beta, передаваемые в функцию должны быть больше 0.
  • gauss(mu, sigma) — на выходе получаются случайные числа, которые соответствуют Гауссовому распределению. В этот метод передаются два параметра: mu — среднее значение и sigma — среднеквадратичное отклонение.
  • lognormvariate(mu, sigma) — генерирует случайные значения соответствующие логарифму нормального распределения. То есть если вычислить натуральный логарифм полученного распределения, то в результате получится нормальное распределение с параметрами mu (среднее) и sigma (среднеквадратичное отклонение).
  • normalvariate(mu, sigma) — предназначен для генерации случайных значений подчиняющихся закону нормального распределения. В качестве параметров передаются: mu — среднее распределения и sigma — стандартное отклонение.
  • vonmisesvariate(mu, kappa) — используется для возврата случайного числа с плавающей запятой с распределением фон Мизеса (или круговым нормальным распределением).
  • paretovariate(alpha) — выдает случайные числа, соответствующие распределению Парето. Параметр alpha задает форму.
  • weibullvariate(alpha, beta) — Значения, выдаваемые weibullvariate соответствуют распределению Вейбулла. Параметр alpha задает масштаб, а beta форму.
💭 Ознакомиться со всеми функциями модуля random можно на официальном сайте Python в разделе документация.

Best practices

Приведем несколько примеров использования случайных чисел.

Пример #1 — случайная задержка (random sleep)

Иногда необходимо сделать так, чтобы программа работала с задержками. Например, это актуально при парсинге сайта (при частых запросах некоторые сайты могут вас банить).

import random import time page_list = ["site.ru/page1", "site.ru/page2", "site.ru/page3"] for page in page_list: # # some actions # time.sleep(random.randint(1, 3)) # задержка от 1 до 3 секунд

💭 Для имитации действий человека можно использовать random.uniform(1, 3) — это добавит случайные миллисекунды к вашим задержкам.

Пример #2 — выбор случайного элемента из списка (с учетом веса)

Дано: веб-сайт. В базе данных 4 баннера, к каждому баннеру указан вес (приоритет к показу).

Необходимо рандомно показывать на сайте 1 баннер, в зависимости от его веса.

import random # данные из БД hero_banners = [ { "id": 1, "name": "SupermanBanner", "weight": 5, }, { "id": 2, "name": "BatmanBanner", "weight": 40, }, { "id": 3, "name": "FlashBanner", "weight": 5, }, { "id": 4, "name": "AquamanBanner", "weight": 40, } ] banner_weights = [banner['weight'] for banner in hero_banners] my_banner = random.choices(hero_banners, banner_weights)[0] print(my_banner) > {'id': 2, 'name': 'BatmanBanner', 'weight': 40}

Пример #3 — случайный пароль

С помощью генератора случайных чисел можно создавать пароли. Например, сгенерировать стойкий пароль можно так:

import random import string pwd_length = 0 while pwd_length < 12: pwd_length = int(input('Укажите длину пароля (от 12 символов): ')) # набор данных (заглавные и строчные буквы, цифры, символы пунктуации) UPPERCASE_CHARACTERS = string.ascii_uppercase LOWERCASE_CHARACTERS = string.ascii_lowercase DIGITS = string.digits SYMBOLS = string.punctuation # весь набор combined_list = UPPERCASE_CHARACTERS + LOWERCASE_CHARACTERS + DIGITS + SYMBOLS # случайный элемент из каждого набора rand_upper = random.choice(UPPERCASE_CHARACTERS) rand_lower = random.choice(LOWERCASE_CHARACTERS) rand_digit = random.choice(DIGITS) rand_symbol = random.choice(SYMBOLS) # temp_pwd = random.sample(combined_list, pwd_length - 4) + [rand_upper, rand_lower, rand_digit, rand_symbol] random.shuffle(temp_pwd) password = "".join(temp_pwd) print(password) > Укажите длину пароля (от 12 символов): 12 > JFyc;6-ICxuQ

В данном примере будет сгенерирован пароль, содержащий минимум 12 символов, среди которых точно будет маленькая буква, большая буква, цифра и символ.


Методы модуля random позволяют получить случайные данные с использованием Mersenne Twister. Однако имейте в виду, что данный способ не является криптографически безопасным (для генерирования паролей есть более надежные варианты).

Кроме модуля random, в Python существуют альтернативные модули, позволяющие получить случайное значения:

  • numpy.random — как random, но для массивов;
  • os — в состав входит urandom() [криптографически безопасный];
  • secrets — модуль для генерации безопасных случайных чисел, байтов и строк [криптографически безопасный];
  • uuid — содержит нескольких функций для создания 128-битных идентификаторов [криптографически безопасный].
😭
😕
😃
😍
закрыть