[MUSIC PLAYING] SPEAKER: Well, hello one and all, and welcome to our short on the random module. Now the random module is a module you can use to add an element of randomness or chance to your programs. And we'll see here, I have a program called cards.py, which I've created by typing code cards.py, and adding in these lines of code on lines 1, 3, 4, and 7 down here. So the goal of cards.py is to simulate kind of dealing from this deck of cards that I have here in the form of this list, one called cards with three cards, jack, queen, and king. But if I want to deal cards, I could think of this element of randomness, shuffling the cards, and dealing them, and seeing what cards I get. And to get somewhat of randomness, we'll need to use the random module. So I can import it up top using import. Import random, just like this. And then down below, I can see a few ways to use the random module with a few functions that are built into it. Now one we've seen is the choice function, which I can get access to by calling random.choice. And .choice here, this function, takes as input some list and returns to me some random element from that list. So I think I could give as input here cards, my list, my deck of cards here, and have it choose for me one card randomly from this deck of three. I could then print the result just like this. If I go down below and type Python of cards.py, we'll see I got back queen from random.choice. Just to prove this is a bit random here, I'll do Python of cards.py, and I get queen again by chance. But let's keep trying. I'll get queen again. I'll do Python of cards.py, and there we go. Now we have a new card again, each one being chosen randomly by chance. So what else is built into the random module? Well, one that can be useful to you, one function, is not just choice, but choices, plural. And choices, true to its name, lets you choose not just one item from a list, but multiple if you wanted to. So let's try that out. I'll go down below and I'll type random.choices. And it turns out, if I read the documentation, I'll find out that choices, this function, takes as input its first argument the same list of options to choose from. And the second argument is one called k, which stands in for number of items I want to randomly choose from this list. So here, let's try choosing two cards instead of just one. I'll set k equal to 2. And now if I go down below and run Python of cards.py, let's see what we get. I'll get queen and king. So it seems like it randomly chose two cards from this deck and got back queen and king. Let's keep trying this again. I'll do python of cards.py, I'll get queen and jack. Python of cards.py, king and jack. And we can keep going here, but-- so here, I seem to have gotten queen and queen, which might not be what you'd expect. Now it turns out that random.choices is doing what's called sampling with replacement. It's akin to me having a deck of three, shuffling it, taking one card out, writing down that card, putting it back in, shuffling again, and choosing another random card from that same deck of three. So every time I choose a new card in this case, I'm choosing from this set of three. When I choose a card, that doesn't eliminate it from future choosing of my random choosing in this particular case. So this is sampling without-- or sampling with replacement. Adding the card, let's say, back into the deck. Now if we don't want that, we want to sample, let's say, without replacement, I could use a different function, one called random.sample. Random.sample. And this one has the same arguments, the first one being the list of cards to choose from, or really any list to choose anything from, and then k being the number of items we hope to select from this list. Now, like I said, random.sample will select without replacement. It will be akin to me having a deck of three, shuffling it, taking one card out, shuffling the remaining two, and choosing one more card. So let's see what happens here. I'll run Python of cards.py, and I'll get back queen and king, two distinct cards. I'll again do Python of cards.py, jack and king. And again, queen and king. So you can see here I'm getting a random set of choices from this deck, but because I only have one card for each, in this case, jack, queen, and king, I'll always get, at the end, unique choices from my deck. I'm here sampling without replacement. Now what if I wanted to maybe weight the odds a little more in my favor and make some things more likely to happen than others? Well, I can actually use, if we go back to random.choices, another argument to this choices function, one called weights. Weights. And weights takes as input this argument here, a list of values, numbers to be sure, the same length as the list that I'm selecting elements from. So let's say I wanted to currently make it more likely a user will choose the jack card. Well, I could do that by adjusting the weights here. Currently, if I didn't set weights at all, it would be equally likely that a user would choose jack, queen, or king. But I could weight things more, let's say, in my favor, and maybe make it so that the user 100% of the time will choose jack. And I can do so like this. Here, 100, indicating 100%, means that the user will always choose the jack card and 0 here, meaning kind of 0%, will be they'll never choose, in this case, queen or king. So let's run this. I'll do Python of cards.py. And here, well, unsurprisingly, we get jack and jack. And we'll run this again, we get jack and jack, and again, we get jack and jack. So it seems like I've weighted things more towards this jack card. But what else could I try? Maybe I could make it only a little bit more likely that a user chooses the jack card. And I'll then make it a little more likely they choose the queen card and king, let's put at about 5%. So to be sure these weights add up to 100%-- of course, we're always going to select at least one card from the options here. But it seems like 75% of the time, we'll get back a jack, 20% of the time, we'll get back a queen, and 5% of the time, we'll get back a king. So let's try this out. I'll run Python of cards.py. Again, get Jack and Jack. Python of cards.py, again, get jack and jack. And if we keep going, odds are we'll eventually, as we have down below, end up with a queen. But again, this is much less likely than it was before without having applied these weights. Now randomness is really fun, really cool, but it's not so fun and not so cool when you're trying to debug your programs. In fact, randomness can get in the way of debugging because really, you want to think of debugging as thinking of defined inputs and defined outputs. And if everything happens randomly, it's hard to debug your program. So thankfully, there are ways to have your programs work with randomness, but to guarantee certain outcomes when you want to do something like debugging. Now in the random module, there is, in this case, a function called seed. And a seed is something that goes into this thing called a pseudorandom number generator. It actually underlies the random choices that go into functions like choices, and sample, and choice that we've seen here. Now it turns out when you initialize a Python program like this one, or call a function like random.choices, you are using that pseudorandom number generator. And it takes as input something like a seed that might change on different runs of your program, like your system time. But if we give a seed that is a specific number that always stays the same, well, we'll always get the same choices from, let's say, a function like random.choices, or sample, or choice. Let's take a look at it here. I'll go down and I will say random.seed, and I'll give it here some number. Let's just say 0 for simplicity. Now normally, the seed would be set by something like my system time. It changes on each run of the program. But here, I want to define it explicitly as 0 every time I run this program. Well, I could go ahead and run Python of cards.py, and we'll see we get back king and king by chance. But now if I run Python of cards.py, I'll get back king and king again, and maybe again here, I'll get back king and king. So it seems like setting the seed has given me a random choice, certainly from this deck, but one that will always stay consistent. And I could try this again. I could do, maybe, a seed of 1, and see if that might change anything here. Python of cards.py. I'll get jack and king here. And I claim that as long as my seed is 1, I'll get back jack and king. So setting the seed here is a really good way to help you debug your programs. Your programs can involve randomness, but you can actually be sure of the outcome when you set something like a random seed. So this was our short on random. Feel free to use it to add an element of chance or randomness to your programs, or whenever you want to set the odds in your favor. This was our short on random. We'll see you next time.