Как получить случайное значение в Python: от random до secrets
Обзор генерации случайных значений в Python
Для получения случайного числа в Python чаще всего используют модуль random стандартной библиотеки. Самая простая функция random.random() возвращает число с плавающей точкой в диапазоне от 0.0 до 1.0 (не включая 1.0). Это базовый строительный блок для большинства случайных операций.
import random
x = random.random()
print(x) # например, 0.6478134628912374Python случайное значение (генерация случайного значения в python)
Функция не принимает аргументов. Если требуется другое распределение или тип, используются специализированные функции модуля. Генератор основан на алгоритме Mersenne Twister, который обеспечивает хорошую равномерность, но не подходит для криптографических задач.
Возможные проблемы:
- При одинаковом начальном значении (
seed) последовательность повторяется. По умолчанию seed = текущее системное время, что даёт разный результат при каждом запуске. - Нельзя получить целое число напрямую. Для целых нужно применять
random.randint()или домножать результат с округлением. - Не криптостойкий: зная несколько последовательных значений, можно предсказать следующие.
Решение: для обычных задач random.random() подходит, для безопасности используйте secrets.
Как сгенерировать случайное целое число в заданном диапазоне?
Используйте random.randint(a, b) или random.randrange(start, stop[, step]).
import random
# целое от 1 до 6 (как бросок кубика)
dice = random.randint(1, 6)
print('Кубик:', dice)
# целое от 0 до 99 с шагом 10
value = random.randrange(0, 100, 10)
print('Шаг 10:', value)randint включает обе границы, randrange исключает верхнюю границу. Если a > b, возникнет ValueError.
Ошибка: пустой диапазон. Например, random.randint(5, 3). Решение: проверять порядок границ перед вызовом.
Как получить случайное число с плавающей точкой в произвольном интервале?
Функция random.uniform(a, b) возвращает случайное float между a и b (включая границы).
import random
# случайное число от 2.5 до 4.0
temp = random.uniform(2.5, 4.0)
print('Температура:', round(temp, 2))Распределение равномерное. Если a > b, функция автоматически переставляет границы.
Особая точность: из-за представления float не все числа в интервале достижимы. Это редко является проблемой.
Как выбрать случайный элемент из последовательности?
Используйте random.choice(seq) для одного элемента, random.choices(seq, k=N) для N элементов с повторениями, random.sample(seq, k=N) для N элементов без повторений.
import random
deck = ['2','3','4','5','6','7','8','9','10','В','Д','К','Т']
# одна случайная карта
card = random.choice(deck)
print('Выбрана:', card)
# три карты с возможными повторами
hand = random.choices(deck, k=3)
print('Рука (повторы):', hand)
# три уникальные карты
hand_unique = random.sample(deck, k=3)
print('Рука (уникально):', hand_unique)Если последовательность пуста, choice вызывает IndexError. sample требует, чтобы k не превышало длину последовательности.
Ошибка: sample с k > len(seq) -> ValueError. Решение: проверить длину.
Как перемешать список случайным образом?
Функция random.shuffle(list) изменяет исходный список, перемешивая его элементы на месте. Возвращает None.
import random
cards = ['2','3','4','5']
random.shuffle(cards)
print('Перемешанный список:', cards)Для создания нового перемешанного списка без изменения исходного используйте random.sample(original, len(original)).
Проблема: shuffle работает только с изменяемыми последовательностями (списки). Кортежи и строки неизменяемы. Решение: преобразовать в список.
Как получить криптографически безопасное случайное значение?
Модуль secrets (Python 3.6+) предназначен для генерации случайных данных, устойчивых к угадыванию. Основные функции: secrets.randbelow(n), secrets.choice(seq), secrets.token_bytes().
import secrets
# безопасное целое от 0 до 99
a = secrets.randbelow(100)
print('Безопасное число:', a)
# безопасный выбор из списка
b = secrets.choice(['A', 'B', 'C'])
print('Выбор:', b)
# 16 случайных байт для токена
token = secrets.token_hex(16)
print('Токен:', token)Эти значения нельзя предсказать, даже зная предыдущие. Используются для паролей, ключей, токенов.
Производительность: secrets медленнее random, поэтому для игр или симуляций предпочтительнее random.
Как сгенерировать случайное целое с заданным количеством бит?
Метод random.getrandbits(k) возвращает целое число, состоящее из k случайных битов (0 или 1).
import random
# 8 бит -> от 0 до 255
bits = random.getrandbits(8)
print('Восьмибитное число:', bits)
# 32 бита
bits32 = random.getrandbits(32)
print('32-бит:', bits32)Это эффективно для генерации целых чисел с точной битовой длиной. Не криптостойко.
При k = 0 возвращается 0. При больших k (например, 10000) создаётся большое целое, операция медленнее.
Расширенные примеры использования генерации случайных значений
Генерация случайного пароля
Для создания надёжного пароля используется модуль secrets и строки символов.
import secrets
import string
def generate_password(length=12):
alphabet = string.ascii_letters + string.digits + string.punctuation
password = ''.join(secrets.choice(alphabet) for _ in range(length))
return password
print('Пароль:', generate_password())Пароль: aK9#2mQ!xR7&
В результат могут войти любые печатные символы. Для исключения неоднозначных символов (например, l,1,O,0) используется собственная строка.
Симуляция броска двух кубиков (2d6)
Сумма двух шестигранных кубиков часто моделируется для настольных игр.
import random
def roll_2d6():
return random.randint(1,6) + random.randint(1,6)
for _ in range(5):
print(roll_2d6())7 11 4 9 5
Можно также использовать random.choices с весами, если распределение неравномерное.
Генерация случайного вещественного числа с нормальным распределением
Функция random.gauss(mu, sigma) возвращает число, подчиняющееся нормальному (гауссову) распределению.
import random
# средний рост 175 см, отклонение 10 см
heights = [round(random.gauss(175, 10), 1) for _ in range(5)]
print('Сгенерированные роста:', heights)Сгенерированные роста: [168.4, 182.7, 171.2, 190.3, 177.6]
Используется для моделирования биологических или физических случайных величин.
Создание независимого генератора с фиксированным зерном
Иногда нужно два независимых потока случайных чисел с разными начальными значениями.
import random
gen1 = random.Random(42)
gen2 = random.Random(12345)
print('gen1:', [gen1.random() for _ in range(2)])
print('gen2:', [gen2.random() for _ in range(2)])gen1: [0.6394267984578838, 0.025010755222666936] gen2: [0.5961458752256162, 0.6591726810325578]
Экземпляры Random не влияют друг на друга и на глобальный генератор.
Генерация случайной даты в заданном диапазоне
Используя random.randint и datetime.timedelta.
import random
from datetime import datetime, timedelta
def random_date(start, end):
delta = end - start
random_days = random.randrange(delta.days)
return start + timedelta(days=random_days)
start = datetime(2020, 1, 1)
end = datetime(2020, 12, 31)
for _ in range(3):
print(random_date(start, end).date())2020-04-15 2020-11-02 2020-07-23
Для больших диапазонов можно использовать секунды или микросекунды.
Перемешивание колоды карт с последующей раздачей
Классический пример: полная колода 52 карты, перемешивание, раздача по 5 карт.
import random
suits = ['пик', 'червей', 'треф', 'бубен']
ranks = ['2','3','4','5','6','7','8','9','10','В','Д','К','Т']
deck = [f'{r} {s}' for s in suits for r in ranks]
random.shuffle(deck)
hand = deck[:5]
print('Карты на руках:', hand)Карты на руках: ['8 треф', 'Д бубен', '5 пик', 'К червей', '7 треф']
Можно использовать random.sample для раздачи без перемешивания всей колоды.