W3docs

Модуль random в Python

Модуль random в Python: генерация случайных чисел, взвешенный выбор, перемешивание, воспроизводимость и криптографическая случайность.

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

  • Генерация случайных чисел с плавающей точкой, целых чисел и диапазонов
  • Выбор случайных элементов: choice, choices, sample
  • Перемешивание последовательностей на месте с помощью shuffle
  • Установка начального значения для воспроизводимых результатов
  • Непрерывные распределения: uniform, gauss, triangular
  • Когда использовать secrets вместо random

Установка не требуется — достаточно import random.

Импорт модуля

import random

Во всех примерах ниже предполагается, что этот импорт выполнен. Можно также импортировать отдельные функции, чтобы не использовать префикс random., хотя префикс явно указывает, откуда берётся каждая функция:

from random import randint, choice, shuffle

Генерация случайных чисел с плавающей точкой

random()

random.random() возвращает число с плавающей точкой в диапазоне [0.0, 1.0) — включая 0.0, но никогда не достигая 1.0.

import random

print(random.random())  # e.g. 0.6394267984578837
print(random.random())  # e.g. 0.025010755222666936

Значение меняется при каждом вызове, потому что генератор продвигает своё внутреннее состояние.

uniform(a, b)

random.uniform(a, b) возвращает число с плавающей точкой N такое, что a <= N <= b:

import random

random.seed(42)
print(random.uniform(1.5, 10.5))  # 7.254841186120954
print(random.uniform(-1.0, 1.0))  # e.g. -0.82  (some float in [-1, 1])

В отличие от random(), функция uniform позволяет задать оба конца диапазона, и верхняя граница может быть возвращена.

Генерация случайных целых чисел

randint(a, b)

random.randint(a, b) возвращает случайное целое число N такое, что a <= N <= b. Оба конца диапазона включительно:

import random

random.seed(42)
die = random.randint(1, 6)
print(die)  # 6

Это наиболее распространённый способ симулировать броски кубика, раздачу карт или любой дискретный целочисленный диапазон.

randrange(start, stop[, step])

random.randrange аналогичен range() Python — stop не включается, и можно задать шаг:

import random

random.seed(42)
# Pick an even number from 0 to 98 (0, 2, 4, ..., 98)
print(random.randrange(0, 100, 2))   # e.g. a random even integer

# Pick a multiple of 5 from 0 to 95
random.seed(42)
print(random.randrange(0, 100, 5))   # 15

Когда нужны случайные целые числа из диапазона, не начинающегося с 0, или требуется шаг, randrange выразительнее, чем randint.

getrandbits(k)

random.getrandbits(k) возвращает случайное неотрицательное целое число с ровно k случайными битами:

import random

random.seed(42)
print(random.getrandbits(8))   # 163 (an integer in 0..255)
print(random.getrandbits(16))  # an integer in 0..65535

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

Выбор из последовательностей

choice(seq)

random.choice(seq) выбирает один элемент случайным образом из непустой последовательности. Работает со списками, кортежами и строками:

import random

random.seed(42)
fruits = ['apple', 'banana', 'cherry']
print(random.choice(fruits))    # cherry

random.seed(42)
print(random.choice('ABCDE'))   # A  (picks one character)

Если последовательность пуста, возникает исключение IndexError.

choices(population, weights=None, k=1)

random.choices выбирает k элементов с возвратом (один и тот же элемент может встречаться более одного раза). Можно задать вероятности с помощью weights:

import random

colors = ['red', 'blue', 'green']

# Equal probability — each run may differ
print(random.choices(colors, k=3))
# e.g. ['blue', 'red', 'red']

# Weighted: green is 3× more likely than red, blue is 2×
random.seed(42)
print(random.choices(colors, weights=[1, 2, 3], k=4))
# ['green', 'red', 'blue', 'blue']

choices всегда возвращает список, даже при k=1. Аргумент weights задаётся в относительных единицах — [1, 2, 3] даёт то же распределение, что и [10, 20, 30].

sample(population, k)

random.sample выбирает k элементов без возврата — каждый элемент может появиться в результате только один раз. Исходная последовательность не изменяется:

import random

random.seed(42)
# Pick 4 unique numbers from 0-9
print(random.sample(range(10), 4))  # [1, 0, 4, 9]

# Simulate a lottery: 6 unique numbers from 1-49
random.seed(7)
ticket = sorted(random.sample(range(1, 50), 6))
print(ticket)  # [4, 5, 10, 21, 26, 42]

Если k больше размера исходной последовательности, random.sample вызывает исключение ValueError:

import random

try:
    random.sample([1, 2, 3], 5)
except ValueError as e:
    print(e)  # Sample larger than population or is negative

Сравнение choices и sample в двух словах:

choicessample
С возвратомДаНет
Дублирующиеся результатыВозможныНикогда
Изменяет оригиналНетНет
Поддерживает весаДаНет (используйте choices)

Перемешивание последовательностей

random.shuffle(seq) перемешивает список на месте и возвращает None. Исходный список изменяется:

import random

random.seed(42)
deck = [1, 2, 3, 4, 5]
random.shuffle(deck)
print(deck)  # [4, 2, 3, 5, 1]  (original list is modified)

Если нужна перемешанная копия без изменения оригинала, используйте random.sample:

import random

random.seed(42)
original = [1, 2, 3, 4, 5]
shuffled = random.sample(original, len(original))
print(original)  # [1, 2, 3, 4, 5]  (unchanged)
print(shuffled)  # [4, 2, 3, 5, 1]

Установка начального значения для воспроизводимых результатов

По умолчанию модуль random инициализируется системным временем (или os.urandom()), поэтому каждый запуск даёт разные значения. Вызов random.seed() с фиксированным значением фиксирует последовательность, чтобы при каждом запуске получался одинаковый результат — это необходимо для отладки, модульных тестов и воспроизводимых симуляций:

import random

random.seed(42)
print(random.random())          # 0.6394267984578837
print(random.randint(1, 10))    # 1
print(random.choice(['a', 'b', 'c']))  # c

# Reset to the same seed — identical sequence
random.seed(42)
print(random.random())          # 0.6394267984578837  (same as before)
print(random.randint(1, 10))    # 1
print(random.choice(['a', 'b', 'c']))  # c

random.seed() принимает целое число, строку, число с плавающей точкой, bytes или None (что повторно инициализирует генератор из системы). Установка начального значения — глобальная операция: она влияет на все последующие вызовы в рамках той же программы, поэтому задавайте начальное значение один раз в начале воспроизводимого блока.

Генерация воспроизводимых тестовых данных

import random

random.seed(999)
test_scores = [round(random.uniform(0, 100), 2) for _ in range(5)]
print(test_scores)  # [78.13, 8.01, 87.25, 57.38, 49.06]

При каждом запуске с seed(999) получается ровно тот же список, что делает это полезным для модульных тестов, проверяющих конкретные значения.

Непрерывные распределения

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

uniform(a, b)

Уже рассмотрено выше — равномерное распределение, при котором каждое значение в [a, b] равновероятно.

triangular(low, high, mode)

Возвращает число с плавающей точкой из треугольного распределения, где mode — наиболее вероятное значение:

import random

random.seed(42)
# Most values cluster near 5, between 0 and 10
t = random.triangular(0, 10, 5)
print(t)  # 5.753983033817951

Полезно, когда известны минимальное, максимальное и наиболее вероятное значения, но точное распределение неизвестно — часто применяется при оценке проектов и моделировании рисков.

gauss(mu, sigma)

Возвращает число с плавающей точкой из гауссова (нормального) распределения со средним значением mu и стандартным отклонением sigma:

import random

random.seed(42)
# Heights in cm: mean 170, std 10
heights = [round(random.gauss(170, 10), 1) for _ in range(5)]
print(heights)  # [168.6, 168.3, 168.9, 177.0, 168.7]

random.normalvariate(mu, sigma) эквивалентен, но потокобезопасен; используйте normalvariate в многопоточных программах.

expovariate(lambd)

Возвращает число с плавающей точкой из экспоненциального распределения, где lambd равно 1 / mean. Полезно для моделирования времени между событиями (например, приходы клиентов, сетевые пакеты):

import random

random.seed(42)
# Mean inter-arrival time = 5 minutes; lambd = 1/5
wait = random.expovariate(1 / 5)
print(round(wait, 2))  # 5.1  (minutes until next arrival)

Практические примеры

Симуляция 60 бросков кубика

import random

random.seed(42)
counts = {face: 0 for face in range(1, 7)}
for _ in range(60):
    counts[random.randint(1, 6)] += 1

print(counts)
# {1: 15, 2: 10, 3: 8, 4: 7, 5: 10, 6: 10}

При большем числе бросков распределение приближается к теоретической вероятности 1/6 для каждой грани.

Случайное формирование команд

import random

random.seed(42)
players = ['Alice', 'Bob', 'Carol', 'Dave', 'Eve', 'Frank']
random.shuffle(players)

team_a = players[:3]
team_b = players[3:]
print('Team A:', team_a)
print('Team B:', team_b)

Простой случайный пароль

Для задач, не требующих безопасности (демонстрации, одноразовые токены), хорошо подходит random.choices:

import random
import string

random.seed(42)
chars = string.ascii_letters + string.digits
password = ''.join(random.choices(chars, k=12))
print(password)  # NbrnTP3fAbnF

Для реальных паролей пользователей или токенов используйте вместо этого модуль secrets (см. ниже).

Когда использовать secrets вместо random

Модуль random не является криптографически стойким. Злоумышленник, наблюдающий достаточно много выходных данных, может предсказать будущие значения. Для всего, что связано с безопасностью, используйте модуль secrets (Python 3.6+), который получает данные из криптографически стойкого источника случайности операционной системы:

import secrets

# Cryptographically secure random integer in [0, 100)
print(secrets.randbelow(100))

# Secure random token for a password-reset link (URL-safe base64)
token = secrets.token_urlsafe(32)
print(token)  # e.g. 'gIg9XzExxFkHLAH9JCK8Zxb1aBEFZ...'

# Secure random hex string for an API key
api_key = secrets.token_hex(16)
print(api_key)  # e.g. 'a3f1c2d4e5b6...'

Правило большого пальца: если вы генерируете токены, идентификаторы сессий, пароли или любые значения, которые злоумышленник не должен угадать, используйте secrets. Для всего остального (игры, симуляции, тестовые данные, выборка) используйте random.

Краткий справочник

ФункцияОписаниеВозвращает
random.random()Число с плавающей точкой в [0.0, 1.0)float
random.uniform(a, b)Число с плавающей точкой в [a, b]float
random.randint(a, b)Целое число в [a, b] (оба конца включительно)int
random.randrange(start, stop[, step])Целое число из range(start, stop, step)int
random.getrandbits(k)Неотрицательное целое число с k случайными битамиint
random.choice(seq)Один случайный элементтип элемента
random.choices(pop, weights, k)k элементов с возвратомlist
random.sample(pop, k)k элементов без возвратаlist
random.shuffle(seq)Перемешать список на местеNone
random.seed(a)Установить начальное значение генератораNone
random.gauss(mu, sigma)Значение гауссова (нормального) распределенияfloat
random.normalvariate(mu, sigma)Нормальное распределение (потокобезопасное)float
random.triangular(low, high, mode)Значение треугольного распределенияfloat
random.expovariate(lambd)Значение экспоненциального распределенияfloat

Связанные главы

  • Python Math — математические функции и константы
  • Python Modules — как импортировать и организовывать модули
  • Python Numbers — целые числа, числа с плавающей точкой и комплексные типы
  • Python Lists — работа с упорядоченными последовательностями
  • Python For Loops — итерации для генерации случайных данных
  • Python Try Except — обработка ошибок, таких как ValueError из sample

Практика

Практика
Which function picks elements without replacement (each item can appear only once in the result)?
Which function picks elements without replacement (each item can appear only once in the result)?
Was this page helpful?