[MUSIC PLAYING] SPEAKER: Well, hello, one and all, and welcome to our short on for loops. If you're familiar with the Mario video game series, you might be familiar with Princess Peach and her castle, Peach's Castle. And we'll imagine together that Princess Peach is inviting some guests to join her at a ball at Peach's Castle at 7:00 PM this evening. Now, thankfully, Peach has automated the process of writing letters to her guests. In fact, we have here a function called write_letter, which takes in two arguments, one called receiver and one called sender. And notice how the purpose write_letter is to return to us a fully written and formatted letter to a receiver from the sender. In particular, we're using Python f-strings here to interpolate the values of receiver and sender. For instance, if our receiver were to be Mario, as it is on line 2 here, and our sender were to be Princess Peach, well, we should see, at the end of this, a letter that says "Dear Mario," and then some text down below, "Sincerely, Princess Peach." And then we'll take that letter and print it out to our terminal to make sure everything is all correct. So let's see what happens if we run this program. I'll go ahead and open up my terminal here. And I'll run python of letters.py. I'll give us a bit more space so we can see all the letters fly by here. If I hit Enter, we'll see some letters being printed out to each of our guests here. We see we invited Mario first. That seems good. Invited Luigi next, Daisy as well, and finally Yoshi. So this program seems to work. But there's a question of how well it's designed. I were to show you again what this program looks like, let's think of some scenarios where this might get a little tedious. Let's say we're only inviting four guests now, but we also want to invite other folks, too, in which case, our guest list gets pretty long. And to do that, I need to copy and paste, copy and paste to add new letters to new characters as well. Now, if you find yourself in this kind of situation where you're repeating something for each maybe guest you have, you might think to use something like a for loop. A for loop, in fact, is great when you know how many times you want to iterate or you want to do something, like write a letter, for each person or each thing you have in some list, like a guest list, in this case. So let's actually make ourselves a guest list and write a for loop to write a letter for each person on that guest list. Well, in main here, why don't I go ahead and update this program to instead keep track of a list that we're going to call names. And this names list will be our guest list for the ball. I'll go ahead and maybe add a few names to the guest list. I'll go ahead and add Mario here and Luigi as well, Daisy too-- Daisy-- and and Yoshi, just like this. And now I have a guest list of names I'm hoping to invite. Well, now what should we do? We know we want to write a letter for each person that is going to be in this list. So I think I can actually get rid of this code down below here and instead think about how I could use a for loop. Well, one way to use a for loop, as we saw in lecture, is to use numbers and iterate over every number in some range of numbers. So I could write some code like this-- for i, which is usually the name we give to some variable that is iterating, changing on each iteration-- for i in-- and then the Python range function. And range will give us a list of numbers from 0 up to but not including the value we pass in as input to range. So in effect, maybe I want i here to iterate, let's say, from 0, maybe the zeroth index of this list, to 1, the first index of this list, to 2, the second index of this list, and then to 3, the third index of this list, again, indexing from 0 with Mario here. So to do that, I can actually pass in to range here the length of our list. Here, I'm saying, len of names, which in this case is 4. But range will give us 0, 1, 2, and 3. Let's try this out though. I'll go ahead and print i down below. And ideally, I'll see 0, 1, 2, and 3, each of the indices in this list here. I'll go ahead and run python of letters.py. And we'll in fact see 0, 1, 2, and 3. That seems to work just as well. But of course, we don't want to invite these numbers to our party. We want to invite Mario, Luigi, Daisy, and Yoshi. So one way to approach this is to use i to index into our list. I could do something like this. I could say names bracket i. And on each iteration, again, i will change. First, it will be 0, then 1, then 2, then 3, giving us different names in our list here. I wanted to go ahead and run letters.py again. And we'll see, now, the names we're hoping to invite. And this is promising because I think I can actually use these as input to the write_letter function. Let's try this. If I were to go ahead and print not just names bracket i but the result write_letter given names bracket i as the receiver and "Princess Peach" as the sender, I think we'd start to get the same letters we saw last time. Notice a few things first here, though. Again, i will update on each iteration of our loop-- that is, from one traversal or time, going from top to bottom in this indented code here. What will actually stay the same is "Princess Peach" here, the name that will be the sender. That will not change on each iteration, because it doesn't depend on anything in our loop itself. So let's go ahead and run this. I'll run Python of letters.py. And we'll see the same letters down below here as well. So same results, but what have we given ourselves here? I'm not able to make this program much more flexible, much more adaptable. How would you invite additional guests? We could very quickly, let's say, add a guest, like Bowser. Everyone is invited here. And we could print out a letter for Bowser, just like that, no copying and pasting, just adding Bowser's name to our guest list. Now let's uninvite Bowser, actually, and think through some ways to improve the design of even this little segment of code here. Now, this works. It's actually pretty well designed. But I think we could make it a little more readable, maybe stylistically better too. And we could do that using a feature of Python, which is we can actually iterate over any kind of list directly. This is a list here. Names is a list of, in this case, names. So we can actually use it as the second part of our for loop. We could say, for i in names. And in this case, i will actually temporarily refer to each of the items in our list, or the names in our names list. i will first be Mario, then Luigi, then Daisy, then Yoshi, updating on each iteration. But I don't need to use i. In fact, I can give it any name I like as long as I am consistent with that name. I could say something more English-like, like, for name in names, because we have a list of names, plural. But each item is a single name, singular. So now on the inside of my for loop, well, there's no longer an i variable to use to index into names. But I've conveniently given myself now this variable called name that I can just use. Again, first name will be Mario, then Luigi, then Daisy, then Yoshi, updating on each iteration as we loop through our for loop. And once we get to the end, once there are no more names, we'll simply stop looping and exit our program. Let's try it here. I'll go ahead and run python of letters.py. And we'll see the same results but now with a bit better English syntax and probably better stylistically as writing programs like these. So for loops, again, are powerful when you know how many times you want to loop or when you want to do something for each item you have in some list or, more generally, some iterable, something can be iterated over. This was our short on for loops. We'll see you next time.