Модуль 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 в двух словах:
choices | sample | |
|---|---|---|
| С возвратом | Да | Нет |
| Дублирующиеся результаты | Возможны | Никогда |
| Изменяет оригинал | Нет | Нет |
| Поддерживает веса | Да | Нет (используйте 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'])) # crandom.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