The random module

Published

2023-08-02

The random module

Consider all the games you’ve ever played that involve throwing dice or shuffling a deck of cards. Games like this are fun in part because of the element of chance. We don’t know how many dots will come up when we throw the dice. We don’t know what the next card to be dealt will be. If we knew all these things in advance, such games would be boring!

Outside of games, there’s a tremendous variety of applications which require randomness.

Simulations of all kinds make use of this—for example, modeling biological or ecological phenomena, statistical mechanics and physics, physical chemistry, modeling social or economic behavior of humans, operations research, and climate modeling. Randomness is also used in cryptography, artificial intelligence, and many other domains. For example, the Monte Carlo method (named after the famous casino in Monaco) is a widely used technique which repeatedly samples data from a random distribution, and has been used in science and industry since the 1940s.

Python’s random module gives us many methods for generating “random” numbers or making “random” choices. These come in handy when we want to implement a game of chance (or game with some chance element) or simulation.

But think: how would you write code that simulates the throw of a die or picks a “random” number between, say, one and ten? Really. Stop for a minute and give it some thought. This is where the random module comes in. We can use it to simulate such events.

I put “random” in quotation marks (above) because true randomness cannot be calculated. What the Python random module does is generate pseudo-random numbers and make pseudo-random choices. What’s the difference? To the casual observer, there is no difference. However, deep down there are deterministic processes behind the generation of these pseudo-random numbers and making pseudo-random choices.

That sounds rather complicated, but using the random module isn’t.

If we wish to use the random module, we first import it (just like we’ve been doing with the math module).

import random

Now we can use methods within the random module.

random.choice()

The random.choice() method takes an iterable and returns a pseudo-random choice from among the elements of the iterable. This is useful when selecting from a fixed set of possibilities. For example:

>>> import random
>>> random.choice(['heads', 'tails'])
'tails'

Each time we call choice this way, it will make a pseudo-random choice between ‘heads’ and ‘tails’, thus simulating a coin toss.

This works with any iterable.

>>> random.choice((1, 2, 3, 4, 5))
2
>>> random.choice(['A', 'K', 'Q', 'J', '10', '9', '8', '7', '6', 
...                '5', '4', '3', '2'])
'7'
>>> random.choice(['rock', 'paper', 'scissors'])
'rock'
>>> random.choice(range(10))
4

It even works with a string as an iterable!

>>> random.choice("random")
'm'

Comprehension check

  1. How could we use random.choice() to simulate the throw of a six-sided die?

  2. How could we use random.choice() to simulate the throw of a twelve-sided die?

Using random.choice() for a random walk

The random walk is a process whereby we take steps along the number line in a positive or negative direction, at random.

Starting at 0, and taking five steps, choosing -1 or +1 at random, a walk might proceed like this: 0, -1, 0, 1, 2, 1. At each step, we move one to the left (negative) or one to the right (positive). In a walk like this there are 2^n possible outcomes, where n is the number of steps taken.

Here’s a loop which implements such a walk:

>>> position = 0
>>> for _ in range(5):
...     position = position + random.choice([-1, 1])
...

random.random()

This method returns the next pseudo-random floating point number in the interval [0.0, 1.0). Note that the interval given here is in mathematical notation and is not Python syntax. Example:

x = random.random()

Here x is assigned a pseudo-random value greater than or equal to zero, and strictly less than 1.

What use is this? We can use this to simulate events with a certain probability, p. Recall that probabilities are in the interval [0.0, 1.0], where 0.0 represents impossibility, and 1.0 represents certainty. Anything between these two extremes is interesting.

Comprehension check

  1. How would we generate a pseudo-random number in the interval [0.0, 10.0)?

Using random.random() to simulate the toss of a biased coin

Let’s say we want to simulate the toss of a slightly biased coin—one that’s rigged to come up heads 53% of the time. Here’s how we’d go about it.

if random.random() < 0.53:
    print("Heads!")
else:
    print("Tails!")

This approach is commonly used in simulations in physical or biological modeling, economics, and games.

What if you wanted to choose a pseudo-random floating point number in the interval [-100.0, 100.0). No big deal. Remember random.random() gives us a pseudo-random number in the interval [0.0, 1.0), so to get a value in the desired interval we simply subtract 0.5 (so the distribution is centered at zero) and multiply by 200 (to “stretch” the result).

x = (random.random() - 0.5) * 200

Comprehension check

  1. How would we simulate an event which occurs with a probability of 1/4?

  2. How would we generate a pseudo-random floating point number in the interval [-2.0, 2.0)?

random.randint()

As noted, we can use random.choice() to choose objects from some iterable. If we wanted to pick a number from one to ten, we could use

n = random.choice([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])

This is correct, but it can get cumbersome. What if we wanted to choose a pseudo-random number between 1 and 1000? In cases like this, it’s better to use random.randint(). This method takes two arguments representing the upper and lower bound (inclusive). Thus, to pick a pseudo-random integer between 1 and 1000:

n = random.randint(1, 1000)

Now we have, n, such that n is an integer, n \geq 1, and n \leq 1000.

random.shuffle()

Sometimes, we want to shuffle values, for example a deck of cards. random.shuffle() will shuffle a mutable sequence (for example, a list) in place. Example:

cards = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 
         'J', 'Q', 'K']
random.shuffle(cards)

Now the cards are shuffled.

Comprehension check

  1. random.shuffle() works with a list. Why wouldn’t it work with a tuple? Would it work with a string?

  2. Where’s the bug in this code?

>>> import random
>>> cards = ['A', '2', '3', '4', '5', '6', '7', '8', '9', 
...          '10', 'J', 'Q', 'K']
>>> cards = random.shuffle(cards)
>>> print(cards)
None
>>>

Other random methods

The random module includes many other methods which include generating random numbers sampled from various distributions, and other nifty tools!

If you are so inclined—especially if you have some probability theory and statistics under your belt—see: randomGenerate pseudo-random numbers: https://docs.python.org/3/library/random.html

Original author: Clayton Cafiero < [given name] DOT [surname] AT uvm DOT edu >

No generative AI was used in producing this material. This was written the old-fashioned way.

This material is for free use under either the GNU Free Documentation License or the Creative Commons Attribution-ShareAlike 3.0 United States License (take your pick).