Модуль random — это модуль стандартной библиотеки Python, который выдает псевдослучайные числа: случайные дроби и целые, выбор элемента из списка, выборку без повторов и перемешивание. Числа только выглядят случайными: их вычисляет детерминированный алгоритм (вихрь Мерсенна) из начального состояния, поэтому для паролей и токенов нужен другой модуль — secrets.
Содержание
Ниже — рабочий пример со всеми основными функциями, таблица «какую функцию взять», воспроизводимость через seed, типичные ошибки и граница безопасности. Все примеры проверены на Python 3.14.7 (сентябрь 2026).
Три термина, которые путают
- Псевдослучайное число — результат формулы, которая по текущему состоянию генератора дает следующее число и новое состояние. Последовательность выглядит случайной, но полностью определяется состоянием.
- Seed (зерно) — значение, из которого генератор строит начальное состояние. Одинаковое зерно — одинаковая последовательность.
- Криптографически стойкий генератор — источник, по выходу которого практически нельзя предсказать следующие значения. Его дает операционная система, в Python к нему ведут
secretsиrandom.SystemRandom.
Цепочка на одном примере: random.seed(42) -> начальное состояние вихря Мерсенна -> первое random.random() всегда 0.6394267984578837.
Минимальный полный пример
Скопируйте и запустите целиком. Зерно зафиксировано, поэтому у вас получится ровно такой же вывод, как в блоке ниже.
import random
random.seed(42)
print(random.random()) # дробь в [0.0, 1.0)
print(random.uniform(5, 10)) # дробь между 5 и 10
print(random.randint(1, 6)) # целое от 1 до 6 включительно
print(random.randrange(10, 100, 2)) # четное от 10 до 98
print(random.choice(["Python", "Java", "Go"]))
print(random.choices([1, 2, 3, 4, 5, 6], k=5)) # с повторами
print(random.sample(range(1, 50), k=6)) # без повторов
deck = list(range(1, 11))
random.shuffle(deck) # меняет сам список
print(deck)
Вывод на Python 3.14.7:
0.6394267984578837
5.125053776113335
3
40
Python
[1, 1, 5, 4, 4]
[3, 2, 6, 14, 15, 33]
[3, 2, 9, 8, 5, 7, 6, 4, 1, 10]
Если убрать строку random.seed(42), при каждом запуске числа будут разными. Обратите внимание на choices: единица и четверка выпали дважды, это нормально для выборки с возвращением.
Какую функцию взять: таблица
| Задача | Функция | Границы и поведение |
|---|---|---|
| Дробь от 0 до 1 | random() |
0.0 входит, 1.0 не входит |
| Дробь в диапазоне | uniform(a, b) |
b может попасть или не попасть из-за округления float |
| Целое в диапазоне | randint(a, b) |
обе границы входят: randint(1, 6) — кубик |
| Целое с шагом | randrange(start, stop, step) |
stop не входит, как в range() |
| Один элемент | choice(seq) |
пустая последовательность — IndexError |
| Несколько с повторами | choices(seq, weights=..., k=n) |
элементы могут повторяться, есть веса |
| Несколько без повторов | sample(seq, k=n) |
k не больше длины, возвращает новый список |
| Перемешать | shuffle(list) |
меняет список на месте, возвращает None |
Критерий выбора между последними тремя простой. Бросок двух кубиков — choices (дубль возможен). Лотерея «6 из 49» — sample (номер не выпадает дважды). Порядок участников или колода — shuffle.
Главная ловушка таблицы — границы: randint(10, 20) может вернуть 20, а randrange(10, 20) — нет. Если сомневаетесь, помните, что randint(a, b) — это то же самое, что randrange(a, b + 1).
Seed и воспроизводимость
Без явного зерна Python инициализирует генератор из источника случайности операционной системы (а если его нет — из текущего времени). Поэтому каждый запуск дает новые числа. Вызов seed с одним и тем же значением возвращает генератор в то же состояние:
import random
random.seed(5)
a = [random.randint(1, 100) for _ in range(3)]
random.seed(5)
b = [random.randint(1, 100) for _ in range(3)]
print(a, b, a == b)
rng = random.Random(2026)
print([rng.randint(1, 6) for _ in range(10)])
[80, 33, 95] [80, 33, 95] True
[1, 3, 5, 5, 6, 1, 2, 5, 5, 5]
Когда это нужно: тесты с одинаковым результатом, отладка «плавающего» бага, эксперименты в анализе данных.
Второй блок показывает более аккуратный прием — отдельный объект random.Random(2026). Функции модуля (random.randint и другие) работают с одним общим генератором, и любая библиотека, которая тоже вызывает random, сдвигает его состояние. Собственный экземпляр изолирован от чужих вызовов.
Граница гарантии: документация Python обещает, что random() с тем же зерном дает ту же последовательность в новых версиях. Для остальных функций (randint, choice, shuffle) алгоритм может измениться между версиями Python. Если воспроизводимость важна надолго (научный расчет, эталонные данные теста), сохраняйте версию Python вместе с зерном или сами результаты.
Веса и распределения
По умолчанию все варианты равновероятны. Чтобы задать вероятности, у choices есть параметр weights:
import random
from collections import Counter
random.seed(1)
colors = ["red", "green", "blue"]
picks = random.choices(colors, weights=[70, 20, 10], k=10_000)
print(Counter(picks))
Counter({'red': 7018, 'green': 1949, 'blue': 1033})
Частоты близки к 70/20/10, но не равны им точно — так и должна вести себя случайная выборка. Для непрерывных распределений в модуле есть gauss, expovariate, triangular, paretovariate и другие. Для массовой генерации в анализе данных обычно берут NumPy (numpy.random.default_rng), это отдельная библиотека.
Типичные ошибки
Ошибка 1: присвоить результат shuffle.
import random
random.seed(7)
cards = ["A", "K", "Q", "J"]
top = random.shuffle(cards)
print(top)
print(cards)
None
['J', 'K', 'A', 'Q']
shuffle ничего не возвращает, а перемешивает сам список. Исправление: вызывать random.shuffle(cards) отдельной строкой и дальше работать с cards. Нужна перемешанная копия без изменения исходника — random.sample(cards, k=len(cards)).
Ошибка 2: неподходящий тип или размер. Проверено на Python 3.14.7, в комментариях — фактический текст исключения:
import random
random.shuffle((1, 2, 3)) # TypeError: 'tuple' object does not support item assignment
random.choice([]) # IndexError: Cannot choose from an empty sequence
random.sample({1, 2, 3}, 2) # TypeError: Population must be a sequence. For dicts or sets, use sorted(d).
random.sample([1, 2, 3], 5) # ValueError: Sample larger than population or is negative
Каждая строка падает сама по себе, поэтому запускайте их по одной. Исправления по порядку: кортеж превратить в список (list(t)), перед choice проверять, что список не пуст, множество передавать как sorted(s), а k держать не больше длины. Ошибка с множеством появилась в Python 3.11: в 3.9 и 3.10 sample еще принимал множество, но с DeprecationWarning, а до 3.9 — молча.
Ошибка 3: называть переменную list или файл random.py. Переменная list затирает встроенный тип, а собственный файл random.py в папке проекта перекрывает стандартный модуль. Симптом второго случая — AttributeError: module 'random' has no attribute 'randint'; с Python 3.13 к сообщению добавляется подсказка «consider renaming ‘…/random.py’». Исправление: переименовать файл. Удалять __pycache__ не обязательно: без исходника random.py устаревший random.cpython-314.pyc оттуда не импортируется.
Граница безопасности: random и secrets
Вихрь Мерсенна не криптостойкий: по достаточно длинному куску его выхода (порядка 624 последовательных 32-битных чисел) можно восстановить внутреннее состояние и предсказать следующие значения. Поэтому random не подходит для паролей, токенов сброса пароля, ключей API, кодов подтверждения и всего, что злоумышленник выиграет, угадав.
Генератор пароля на secrets:
import secrets
import string
ALPHABET = string.ascii_letters + string.digits + "!#$%&*+-=?@_"
def make_password(length: int = 16) -> str:
if length < 8:
raise ValueError("слишком короткий пароль")
while True:
pwd = "".join(secrets.choice(ALPHABET) for _ in range(length))
if (any(c.islower() for c in pwd)
and any(c.isupper() for c in pwd)
and any(c.isdigit() for c in pwd)):
return pwd
pwd = make_password()
print(len(pwd), pwd.isascii())
token = secrets.token_urlsafe(32)
print(len(token))
16 True
43
Сам пароль каждый раз новый, поэтому печатаем только проверяемые свойства: длину и то, что он состоит из ASCII. token_urlsafe(32) берет 32 случайных байта и кодирует их в base64 без символов, опасных для URL, получается 43 знака. У secrets нет функции seed — и это правильно: стойкий генератор не должен быть воспроизводимым.
Стойкий генератор решает только одну задачу — непредсказуемость. Хранение пароля (хеширование медленной функцией вроде Argon2id), ограничение числа попыток входа и срок жизни токена — отдельные меры, secrets их не заменяет.
Если не получилось
- Числа повторяются при каждом запуске — где-то в коде или в импортируемой библиотеке вызывается
random.seedс константой. Уберите его или заведите свойrandom.Random(). AttributeErrorпроrandint— файл проекта называетсяrandom.py.- Получили
Noneвместо списка — присвоили результатshuffle. randintиногда выдает верхнюю границу, хотя не ожидали — нуженrandrange.- В Python 3.13+ быстро проверить модуль можно из терминала:
python -m random 6печатает целое от 1 до 6,python -m random a b c— один из вариантов.
Выводы
randomдает псевдослучайные числа: последовательность определяется зерном и подходит для игр, симуляций и тестов.randint(a, b)включает обе границы,randrangeне включает stop,choicesповторяет элементы,sample— нет,shuffleменяет список и возвращаетNone.seedили отдельныйrandom.Random(seed)делают результат воспроизводимым; между версиями Python гарантия дана только дляrandom().- Для паролей, токенов и кодов подтверждения нужен
secrets, а неrandom.
Где применяется / связь с практикой
Тестовые данные, перемешивание выборки перед обучением модели, игры, одноразовые коды в веб-приложении — везде сначала решают, нужна воспроизводимость или непредсказуемость, и только потом выбирают random или secrets.
Освойте тему на практике
Если хочется системно пройти основы языка — типы, функции, модули стандартной библиотеки, работу с файлами и тесты, — посмотрите программу курса Python Developer. Basic. Разобраться в отдельных темах с преподавателями можно на бесплатных открытых уроках Otus.
FAQ
Можно ли получить в Python по-настоящему случайное число?
secrets и random.SystemRandom берут данные из генератора операционной системы, который подмешивает аппаратные источники энтропии. Для прикладных задач этого достаточно, отдельное «квантовое» железо не требуется.
Как получить случайное число с двумя знаками после запятой?
round(random.uniform(0, 100), 2) или форматирование при выводе f"{x:.2f}". Для денежных сумм удобнее генерировать целые копейки через randint и делить при выводе.
Потокобезопасны ли функции random?
Вызовы общего генератора из разных потоков не ломают его состояние, но порядок чисел между потоками непредсказуем. Исключение из документации — gauss: два потока, вызвавшие его одновременно, могут получить одно и то же значение (для потоков берут normalvariate или свой генератор). Для воспроизводимости в многопоточном коде заводите по отдельному random.Random(seed) на поток.



