Каппес Даниил Олегович

ПРАКТИКУМ PYTHON · ЗАНЯТИЕ 🎲

Модуль random

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

Зачем нужны случайные числа

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

Случайные числа нужны не только играм:

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

Функции для работы со случайностью лежат в модуле random стандартной библиотеки, и его надо подключить:

import random

Случайные числа

randint(a, b) возвращает случайное целое число из отрезка [a; b]. Обе границы включаются:

import random

num1 = random.randint(0, 17)    # от 0 до 17 включительно
num2 = random.randint(-5, 5)    # от -5 до 5 включительно
print(num1)
print(num2)

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

import random

for _ in range(10):
    print(random.randint(1, 100))

randrange() принимает те же аргументы, что и range(), но возвращает не последовательность, а одно случайно выбранное из неё число:

random.randrange(10)          # от 0 до 9
random.randrange(5, 10)       # от 5 до 9
random.randrange(0, 101, 10)  # одно из чисел 0, 10, 20, …, 100

Разница между ними ровно в правой границе: у randint(0, 10) десятка может выпасть, у randrange(0, 10) — нет. Это тот же принцип, что и у range().

random() возвращает вещественное число от 0.0 до 1.0 (единица не включается) и не принимает аргументов, а uniform(a, b) — вещественное число из заданного промежутка:

import random

print(random.random())          # например, 0.7203244934421581
print(random.uniform(1.5, 17.3))

Случайный выбор из списка

choice() возвращает один случайный элемент списка или строки:

import random

print(random.choice('BEEGEEK'))
print(random.choice([1, 2, 3, 4]))
print(random.choice(['a', 'b', 'c', 'd']))

Результат

E
3
c

sample(последовательность, k) возвращает список из k случайных элементов — все разные:

import random

numbers = [2, 5, 8, 9, 12]
print(random.sample(numbers, 2))
print(random.sample(numbers, 5))

Результат

[12, 5]
[12, 8, 9, 5, 2]

Просить больше элементов, чем есть, нельзя: random.sample(numbers, 6) при пяти элементах останавливает программу — ValueError: Sample larger than population or is negative.

shuffle() перемешивает список на месте — как sort(), только наоборот:

import random

numbers = [1, 2, 3, 4, 5, 6, 7, 8]
random.shuffle(numbers)
print(numbers)

Результат

[4, 7, 8, 1, 2, 3, 6, 5]

shuffle() ничего не возвращает — как и sort(). Писать numbers = random.shuffle(numbers) нельзя: список окажется пустым.

Почему числа не совсем случайные

Числа, которые выдаёт random, называют псевдослучайными: они вычисляются по формуле. Формуле нужно начальное значение — его модуль берёт из системных часов в момент подключения. Часы меняются каждую сотую долю секунды, поэтому при каждом запуске ряд получается новым.

Иногда нужен, наоборот, повторяемый ряд — например, чтобы отладить программу на одних и тех же данных. Тогда начальное значение задают сами:

import random

random.seed(17)   # с этого зерна ряд будет одним и тем же
for _ in range(10):
    print(random.randint(1, 100))

Запустив такую программу дважды, вы получите одинаковые числа — и это не поломка, а именно то, о чём попросили.

Подключить модуль можно и так: from random import *. Тогда имя модуля и точку перед функциями писать не нужно: randint(1, 6) вместо random.randint(1, 6).

Три разобранные задачи

Задача 1. Профессор Тимур преподаёт вводный курс статистики и просит программу, имитирующую бросок двух игральных кубиков.

import random

print('Бросаем кубики...')
print('Значения граней:')
print(random.randint(1, 6))
print(random.randint(1, 6))

Грани кубика — числа от 1 до 6 включительно, поэтому randint() подходит точно: обе границы входят.

Задача 2. Тот же профессор хочет бросать кубики несколько раз подряд — пока не надоест.

import random

again = 'д'
while again.lower() == 'д':
    print('Бросаем кубики...')
    print('Значения граней:')
    print(random.randint(1, 6))
    print(random.randint(1, 6))
    again = input('Бросить кубики ещё раз? (д = да, н = нет): ')

Сколько будет бросков, заранее неизвестно — значит, while. А lower() позволяет отвечать и «Д», и «д».

Задача 3. Нужен симулятор десяти подбрасываний монеты: каждый раз выпадает орёл или решка.

import random

for _ in range(10):
    num = random.randint(0, 1)
    if num == 0:
        print('Орел')
    else:
        print('Решка')

Здесь случайное число играет роль монеты: два исхода — два возможных значения. Тот же приём годится для любого выбора из нескольких вариантов: сгенерировать номер и разобрать его развилкой.

Есть и короче: print(random.choice(['Орел', 'Решка'])). Выбирайте тот вариант, который понятнее вам самим, — оба верны.