Python random
Core Python Functions and Modules

Python random Module

1Python random: overview

The random module draws pseudo-random numbers and picks from a seeded generator, so you can simulate dice, shuffle and sample lists, and repeat exactly the same results whenever you fix the seed.

GoalBy the end you can generate numbers and picks with random(), randint, choice, choices, sample and shuffle, make results repeatable with seed, keep a private generator with Random(), and know when to use secrets instead.

Before this lesson: Python Lists, Python Modules and Imports

2Python random: diagram

Which random function do you need?Which random function do you need?You wantCallGood to knowa float from 0 up to 1random()1.0 itself never appearsa float in a rangeuniform(a, b)any float between a and ba whole number, both endsrandint(a, b)b is includeda whole number, like rangerandrange(a, b)b is NOT includedone item from a listchoice(items)empty list: IndexErrork items, repeats allowedchoices(items, k=3)accepts weightsk items, no repeatssample(items, 3)k cannot exceed lenreorder a listshuffle(items)in place, returns NoneCall random.seed(n) first and every row gives the same answers on every run
Pick the row that matches what you need. Near-twins such as randint and randrange, or choices and sample, differ in one detail, and that detail is the cause of most random-module bugs.

3Python random: explained step by step

The numbers from random are not truly random. They come from a formula that starts from a number called the seed, and that is a feature: if you start from the same seed, you get exactly the same "random" sequence again. Games leave the seed alone so every play is different. Tests, simulations and tutorials fix it so results can be repeated. Every snippet on this page calls random.seed(...) first, so what you see is what you get.

Seeding: same seed, same numbers

random.seed(42) puts the generator into a known starting state. Seed again with the same value and the sequence starts over.

Python
import random

random.seed(42)
print(random.random(), random.random())

random.seed(42)
print(random.random())

Seed once, at the start of the program. Seeding again inside a loop restarts the sequence every time (see the mistakes below). Without a call to seed, Python seeds itself from the operating system, so each run differs.

Numbers: random, uniform, randint, randrange

Python
import random

random.seed(1)
print(random.random())
print(random.uniform(10, 20))
print(random.randint(1, 6))
print(random.randrange(0, 10, 2))

random() gives a float from 0 up to (not including) 1, and uniform(a, b) a float between a and b. For whole numbers there are two near-twins. randint(a, b) includes both ends, so randint(1, 6) is a die. randrange(a, b) works like range() and stops before b; a third argument sets the step, so randrange(0, 10, 2) is one of 0, 2, 4, 6, 8. To pick a position in a list, use randrange(len(items)).

Picking from a list: choice, choices, sample

  • choice(items) returns one item, and raises IndexError on an empty list.
  • choices(items, k=3) draws 3 items with replacement, like putting each card back, so repeats can happen. It always returns a list, even for k=1, and accepts weights= to make some items likelier.
  • sample(items, 3) draws 3 items without replacement, like dealing cards: nothing appears twice. Asking for more items than the list holds is a ValueError.
Python
import random

random.seed(3)
colors = ["red", "green", "blue", "gold"]
print(random.choice(colors))
print(random.choices(colors, k=5))
print(random.choices(colors, weights=[10, 1, 1, 1], k=5))
print(random.sample(colors, 2))

Use choices for independent events (a weighted loot drop) and sample for winners, teams or a hand of cards.

shuffle: reorder a list in place

random.shuffle(items) rearranges the list itself and returns None. Do not assign its result. It needs a mutable list, so a tuple fails with a TypeError. When you need the original order as well, copy first, or use sample(items, k=len(items)), which returns a new shuffled list.

Python
import random

random.seed(8)
deck = ["A", "K", "Q", "J"]
original = list(deck)
result = random.shuffle(deck)
print(result)
print(deck, original)
print(random.sample(original, k=len(original)))

Your own generator: random.Random(seed)

The functions above share one hidden generator. If two parts of a program both draw from it, they disturb each other's sequence. random.Random(seed) creates a private generator with the same methods (randint, choice, shuffle and the rest) and its own state.

Python
import random

dice = random.Random(10)
cards = random.Random(10)
print([dice.randint(1, 6) for _ in range(5)])
print([cards.randint(1, 6) for _ in range(5)])

rng = random.Random(5)
first = rng.randint(1, 100)
random.random()
second = rng.randint(1, 100)
check = random.Random(5)
print([first, second] == [check.randint(1, 100), check.randint(1, 100)])

The same seed gives the same stream, and drawing from the shared generator in between changes nothing. That makes a private generator the right choice for a function that must be reproducible, such as a test-data builder.

Simulations: dice, coins and events

Put a draw in a loop and you have a simulation. A coin flip is choice(["heads", "tails"]), and an event with a 25% chance is rng.random() < 0.25.

Python
import random

rng = random.Random(7)
rolls = [rng.randint(1, 6) for _ in range(600)]
for face in range(1, 7):
    print(face, rolls.count(face))
hits = sum(rng.random() < 0.25 for _ in range(1000))
print("Events at 25%:", hits, "out of 1000")

The counts are near 100 each, never exactly 100. More trials land closer to the expected share. A guessing game follows the same pattern: draw secret = rng.randint(1, 100) once, then compare each guess with it.

Passwords and tokens: use secrets

random is predictable: whoever learns the seed, or enough outputs, can work out what comes next. For passwords, reset links and API tokens use the secrets module. It draws from the operating system's secure source and cannot be seeded, so its results can never be reproduced.

Python
import secrets

token = secrets.token_hex(8)
pin = "".join(secrets.choice("0123456789") for _ in range(6))
print(len(token), len(pin), pin.isdigit())

Only the lengths are printed because the values change on every run, and a real secret should never be printed or logged.

Which one should I use?

Use random for games, simulations and sample data, with a seed when you need repeatable results. Use secrets for anything an attacker would like to guess.

Quick reference: Python random

4Python random: syntax

import random
random.seed(42)                        # repeatable results (call once, at the start)
random.random()                        # float: 0 <= x < 1
random.uniform(a, b)                   # float between a and b
random.randint(a, b)                   # whole number, a and b both possible
random.randrange(start, stop, step)    # like range(): stop is excluded
random.choice(items)                   # one item
random.choices(items, weights=None, k=1)   # list of k items, repeats allowed
random.sample(items, k)                # list of k different items
random.shuffle(items)                  # reorders the list in place, returns None

rng = random.Random(42)                # private generator with its own seed
rng.randint(1, 6)                      # same methods as the module

import secrets
secrets.token_hex(16)  secrets.choice(items)   # secure, never repeatable

5Python random: run the example

Press Run (or Ctrl + Enter). The output (step 6) appears directly below the code. Change anything and run it again.

Interactive example
import random

random.seed(21)

suits = ["S", "H", "D", "C"]
ranks = ["A"] + [str(n) for n in range(2, 11)] + ["J", "Q", "K"]
deck = [rank + suit for suit in suits for rank in ranks]
random.shuffle(deck)

asha_hand = deck[:5]
ben_hand = deck[5:10]
print("Asha:", asha_hand)
print("Ben:", ben_hand)
print("Cards left:", len(deck) - 10)

lucky = random.choice(asha_hand)
print("Asha plays", lucky)
Expected outputAsha: ['7S', '9C', '3D', '4H', '9S']
Ben: ['6S', 'AC', 'KH', '5C', '9H']
Cards left: 42
Asha plays 9C

7Python random: how the example works

Hover or tap a step to highlight its lines in the example above.

  1. Line 1Import the random module.
  2. Line 3random.seed(21) fixes the starting state, so the shuffle below is the same on every run. Remove this line and the hands change each time.
  3. Line 5-7Build a 52-card deck: 4 suits times 13 ranks. The list comprehension joins a rank and a suit into one string, such as "10H".
  4. Line 8random.shuffle(deck) reorders the list in place and returns None, so the result is not assigned to anything.
  5. Line 10-11Slicing deals the cards. Asha gets the first five, Ben the next five, and no card can go to both players.
  6. Line 12-13Printing each hand shows the cards in the order they were dealt.
  7. Line 1452 cards minus the 10 dealt leaves 42 in the deck.
  8. Line 16-17random.choice() picks one card from Asha's hand. It draws from the same seeded generator, so this pick is repeatable too.

8Python random: common mistakes

Using randint(0, len(items)) as an index

✗ Wrong

import random

random.seed(0)
moves = ["rock", "paper", "scissors"]
print(moves[random.randint(0, len(moves))])
IndexError: list index out of range

✓ Right

import random

random.seed(0)
moves = ["rock", "paper", "scissors"]
print(random.choice(moves))

randint includes its upper end, so randint(0, 3) can return 3, but a three-item list stops at index 2. Use random.choice(moves), or random.randrange(len(moves)), which never reaches the length.

Assigning the result of shuffle()

✗ Wrong

import random

cards = ["A", "K", "Q", "J"]
shuffled = random.shuffle(cards)
print(shuffled)
No error, but it prints None

✓ Right

import random

cards = ["A", "K", "Q", "J"]
random.shuffle(cards)
print(cards)

shuffle() reorders the list in place and returns None. Call it on its own line and use the original list, or use random.sample(cards, k=len(cards)) to get a new shuffled list.

Shuffling a tuple

✗ Wrong

import random

weekdays = ("Mon", "Tue", "Wed")
random.shuffle(weekdays)
print(weekdays)
TypeError: 'tuple' object does not support item assignment

✓ Right

import random

random.seed(5)
weekdays = ("Mon", "Tue", "Wed")
print(random.sample(weekdays, k=len(weekdays)))

A tuple cannot be changed, and shuffle works by swapping items in place. Make a shuffled list with random.sample(), or convert the tuple with list() first.

Calling seed() inside the loop

✗ Wrong

import random

for roll in range(3):
    random.seed(5)
    print(random.randint(1, 6))
No error, but it prints 5 three times

✓ Right

import random

random.seed(5)
for roll in range(3):
    print(random.randint(1, 6))

Every seed(5) rewinds the generator to the same starting point, so it repeats its first number. Seed once, before the loop.

Sampling more items than the list holds

✗ Wrong

import random

random.seed(1)
names = ["Asha", "Ben", "Cara"]
print(random.sample(names, 5))
ValueError: Sample larger than population or is negative

✓ Right

import random

random.seed(1)
names = ["Asha", "Ben", "Cara"]
print(random.sample(names, min(5, len(names))))

sample() never repeats an item, so it cannot return more items than the list has. Ask for at most len(names), or use random.choices(names, k=5) if repeats are fine.

9Python random: exercises

Write your answer, then press Check. The checks run in your browser.

1. Roll the dice

Write code Easy

Write a function roll_dice(count) that returns a list of count random die rolls. Every roll is a whole number from 1 to 6, and 6 must be possible. Use random.randint.

Your code
import random

def roll_dice(count):
    # return a list of count rolls, each from 1 to 6
    pass

random.seed(11)
print(roll_dice(5))

2. Predict the random facts

Predict the output Easy

Nothing here depends on lucky numbers: every line prints something you can work out. Type exactly what the program prints, then press Check.

Read this code
import random

random.seed(1)
first = random.randint(1, 6)
random.seed(1)
second = random.randint(1, 6)
print(first == second)

cards = ["A", "K", "Q"]
result = random.shuffle(cards)
print(result)
print(sorted(cards))
print(len(random.sample(range(10), 4)))
print(random.randint(5, 5))

2 more exercises → 6 more examples

Finished this lesson?
Progress is saved in this browser — create a free account to keep it across devices.

Questions learners ask

Is Python's random module really random?

No, it is pseudo-random. A formula (the Mersenne Twister) produces numbers that look random and pass statistical tests, but the whole sequence is decided by the seed. That is perfect for games, simulations and sample data. It is not safe for passwords, tokens or anything an attacker might guess. For those use the secrets module, which draws from the operating system's secure source.

How do I get the same random numbers every time I run my program?

Call random.seed(some_number) once, before any other random calls. The same seed always produces the same sequence, so your tests and bug reports become repeatable. If different parts of the program need their own repeatable streams, create private generators with random.Random(seed) so they cannot disturb each other.

What is the difference between random.choice, random.choices and random.sample?

choice(items) returns one item. choices(items, k=n) returns a list of n items drawn with replacement, so repeats are possible, and it supports weights. sample(items, n) returns a list of n different items drawn without replacement, like dealing cards, and raises ValueError if n is larger than the list.

Further reading

10Next lesson

Up nextPython datetime ModuleThe datetime module gives you date, time, datetime and timedelta objects that understand the calendar, so you can forma…

Related:
Python else on LoopsPython List MethodsPython Modules and ImportsPython math and statistics

← Python math and statistics · All Functions and Modules lessons · Practise in the IDE