## Chapter 7, Lesson 3 Text

## Lesson Three: Random Numbers

Normally, computers are very predictable. However, your program may occasionally need to do something unexpected or **random**. Imagine a computer game where you want to generate a random number, secret code or shuffle a deck of cards. In this lesson, you'll learn about Python's functions for generating random numbers and picking random items from lists.

### Using the "random" Module

All of Python's randomization functions are in the random module. So, any time you want to use these functions, you must first add the "**import random**" statement at the top of your code.

`import random`

Unlike the **datetime** library, which contains multiple objects that have their own functions and properties, the **random** library is typically used as a collection of independent functions. This means you can perform all the **random** operations simply by writing the module name, **random**, then a** dot (.)** and the **function name** that you want to call.

### Generating Random Integers with randrange()

Random integers are useful in many applications. To generate a random integer between some minimum and maximum values, simply call the **random**.**randrange**() function. The first parameter is the **minimum** possible value and the second parameters is **one more** than the **largest** possible value. Therefore, **randrange**(0,10) will return a random number starting at 0 and going up to and including 9, but will never return 10.

`random.randrange(<min>,<max>) # returns random integer from <min> through <max> - 1`

Let's create some random numbers. The example below will loop 5 times and print a random number from 0 through 9 on each loop. Every time you run the program, you should see a difference sequence of random numbers. Try it and see!

Try It Now

You may remember from Chapter 3, Lesson 1 that the **print**() statement can take an optional "**end**" parameter to replace the default "new line" with some other character such as a space. We've added **end=" "** to our **print**() above to keep all the random numbers printed on the same line.

### The randint() Alternative

The **random** library defines another function called **randint**() that works very similarly to **randrange**(). However, the **maximum value can be returned by** **randint**(), so **randint**(0,10) will actually return the value 10 as well as 0 through 9.

`random.randint(<min>,<max>) # returns random integer from <min> through <max>`

It can be confusing to keep track of two similar functions that behave "almost" the same way. For consistency, we'll use randrange() instead of randint() in our examples and activities. Just be aware of the difference in case you see randint() in someone else's code.

### Seeding the Random Number Generator

It may come as a surprise, but it's hard for computers to produce truly random results. Most random number generators are complex algorithms that give you **pseudo-random** (or mostly random) results that are good enough for everyday use. These algorithms use some input data as a **starting point** or **seed** in order to generate the pseudo-random results.

By default, the random library will use the **current time** as the starting point for generating random numbers. Since the current time changes continuously, this gives the computer a reasonably "random" seed for the random number generator.

You can set your own starting point by calling the **random**.**seed**() function. You can pass any numeric or string value into **seed**(), and that data will be used internally to initialize the random number generator.

`random.seed(<any value>) # re-initialize random number generator with this seed`

The **most important thing **about **seed**() is that it allows you to generate the same sequence of "random" numbers each time you call **seed**() with the same value! For example, you might want a computer game to generate a new random challenge for players at each level, but you want every level to be the same for all players. One way to do this is to seed the random number generator with a known value before you generate each level.

To see this concept in action, look at the code below. We call **random**.**seed**() with a known value (simply 1), and then generate 10 random numbers from 0 up through 99. We then call **random**.**seed**() again with the same value and generate 10 more random numbers. Run the code to see the results.

Try It Now

Both sets of random numbers are the same, because the starting seed was the same in each sequence!

### Random Elements from Lists

The **random** module contains the **choice**() function, which allows you to get an element at random from an input list or tuple. The input list is not changed but copy of a random element will be returned each time you call **random**.**choice**().

`random.choice(<list or tuple>) # get random value from input collection`

In the example below, we have defined a **tuple** with 4 elements. We then use a "**for**" loop to iteration 10 times, calling **random**.**choice**() on the tuple each time and printing the result to the screen.

Try It Now

When you run this code, you should see 10 random colors printed to the screen. The results will be different on each run because we have not specified any fixed starting seed.

### Shuffling Lists

The random library also allows you to shuffle the contents of a list, putting the elements in a random order. The **random**.**shuffle**() function will perform this trick. Of course, **shuffle**() will not work on tuples, because tuples can't be changed.

`random.shuffle(<list>) # re-order list elements randomly`

In the example below, we have defined a list with 10 elements, initially in an obvious order. We then call **random**.**shuffle**() to mix up the list contents and print the results to the screen.

Try It Now

Each time you run this code, the **shuffle**() function should change the list in a different random order.

### Real (Decimal) Random Numbers

The last common **random** feature we'll discuss is the generation of random **decimal** values. Simply call the **random**() function to produce a value between 0.0 and 1.0. The lower limit 0.0 is a possible output, while you will never get all the way up to 1.0 (but you might get very close as in .99999).

`random.random() # produce random decimal value between 0.0 and 1.0`

If you'd rather get a random value within a specific range, you can call the **uniform**() function with upper and lower bounds.

`random.uniform(<min>,<max>) # produce random decimal value between <min> and <max>`

To see these two functions in action, run the code below. We generate three random numbers with **random**() and then three more with **uniform**(). The **uniform**() min and max values are set at -5.0 and 5.0, so you should see random results in that range.

Try It Now

Both **random**() and **uniform**() give results that are **evenly distributed **across the entire range. A value near the minimum or maximum is as likely to be chosen as a value near the middle. The **random** module has other functions that produce different kinds of results, such as a bell curve where numbers near the middle are the most likely to be chosen. To read more about the **random** module, click on the link below to see the official Python documentation.

https://docs.python.org/3/library/random.html

Work with Me: Games of Chance

Random values have many useful applications. In this exercise, you are going to shuffle a deck of cards, pull a random card from the deck and flip a coin 5 times to see the results. Here is some sample output.

['Queen', '6', '9', '10', 'Ace', 'King', '5', '2', '7', '4', '8', 'Jack', '3'] Card at index 6 = '5' Coin-flip results: Heads Coin-flip results: Heads Coin-flip results: Tails Coin-flip results: Tails Coin-flip results: HeadsRemember, the index into a list is zero-based, so index 6 refers to the 7th element in the list.

We are giving you a little bit of starter code that defines a 13-card list (2 through Ace) and a tuple of coin-flip options ("Heads" and "Tails"). Follow the steps below to finish the code on your own.

- Shuffle the deck of cards and then print the resulting list to the screen
- Create a variable called
cardIndexand set it equal to a random integer in the range 0 up through and including 12. This integer can be used to pull a specific element at that position from the deck of cards.- Create a variable called
cardand set it equal to thedeckelement at thecardIndexposition (deck[cardIndex]).- Print the following formatted message to the screen: "
Card at index <X> = '<Card>'". Usestr.format() to create the message.- Inside the "
for" loop (already written for you)

- Create a variable called
flipand set it equal to a random element pulled from thecoinFlipOptionstuple. Use therandom.choice() function to get a random element.- Print the formatted string "Coin-flip results: <flip>"
Try It Now

import randomdeck = ["2","3","4","5","6","7","8","9","10","Jack","Queen","King","Ace"]# shuffle the deck# print the results# get random card index from 0 through 12# get and print card at that positioncoinFlipOptions = ("Heads","Tails")for i in range(0,5):# get random choice from coinFlipOptions and print resultsConsole

You should get different results each time you run the program. The example below shows another valid run.

['2', 'Queen', 'Ace', '8', 'King', '5', '6', '9', '4', '3', 'Jack', '7', '10'] Card at index 2 = 'Ace' Coin-flip results: Tails Coin-flip results: Tails Coin-flip results: Heads Coin-flip results: Tails Coin-flip results: Tails