1 00:00:00,000 --> 00:00:03,451 [MUSIC PLAYING] 2 00:00:03,451 --> 00:00:24,160 3 00:00:24,160 --> 00:00:25,180 DAVID MALAN: All right. 4 00:00:25,180 --> 00:00:28,540 This is CS50's Introduction to Programming with Python. 5 00:00:28,540 --> 00:00:33,010 My name is David Malan, and this week we focus on loops, this ability in Python 6 00:00:33,010 --> 00:00:37,000 and a lot of other programming languages to do something again and again, 7 00:00:37,000 --> 00:00:38,500 a cycle of sorts. 8 00:00:38,500 --> 00:00:40,420 And let's see if we can't begin by motivating 9 00:00:40,420 --> 00:00:45,310 exactly why we have this ability to do things cyclically using these loops. 10 00:00:45,310 --> 00:00:48,130 I'm going to go ahead here and open up VS Code. 11 00:00:48,130 --> 00:00:50,260 And in my terminal window, let's go ahead 12 00:00:50,260 --> 00:00:57,100 and create via code cat.py, a Python program that meows like a cat. 13 00:00:57,100 --> 00:01:00,910 And I'm going to go ahead here in this Code tab, and very simply, perhaps, 14 00:01:00,910 --> 00:01:03,760 I'm going to start by implementing this cat just by using print. 15 00:01:03,760 --> 00:01:06,010 We're going to have this cat not make audible sounds, 16 00:01:06,010 --> 00:01:08,860 but just print meow, meow, meow on the screen three times. 17 00:01:08,860 --> 00:01:12,640 Well, I think the simplest way I can do this is just to print meow once, 18 00:01:12,640 --> 00:01:18,590 and to print meow again, and to print meow one last time on the screen. 19 00:01:18,590 --> 00:01:23,320 And now let me go down to my terminal window, let me run Python of cat.py, 20 00:01:23,320 --> 00:01:25,480 Enter, and meow, meow, meow. 21 00:01:25,480 --> 00:01:27,670 All right, so this program works. 22 00:01:27,670 --> 00:01:31,120 This program indeed works if my goal is to get the cat to meow three times. 23 00:01:31,120 --> 00:01:34,280 And let me propose, just to help us wrap our minds around 24 00:01:34,280 --> 00:01:36,430 what's going on inside of the computer, let 25 00:01:36,430 --> 00:01:38,810 me propose that we consider this flowchart. 26 00:01:38,810 --> 00:01:40,810 So as before, we have this flowchart that 27 00:01:40,810 --> 00:01:44,140 starts with this oval, which just means start reading here. 28 00:01:44,140 --> 00:01:50,050 And then notice, it goes via arrows to a meow, meow, meow, and then it stops. 29 00:01:50,050 --> 00:01:53,890 It's perfectly correct, and honestly, it's wonderfully simple, 30 00:01:53,890 --> 00:01:58,090 but I daresay we can find fault with my code nonetheless. 31 00:01:58,090 --> 00:02:03,550 Why is my code arguably poorly designed? 32 00:02:03,550 --> 00:02:05,680 Now the answer is going to be loops in some way, 33 00:02:05,680 --> 00:02:08,169 but let's see if we can identify in what way 34 00:02:08,169 --> 00:02:12,950 the code is actually poorly designed in some sense. 35 00:02:12,950 --> 00:02:13,660 Let's see. 36 00:02:13,660 --> 00:02:14,260 Any thoughts. 37 00:02:14,260 --> 00:02:15,608 Alex? 38 00:02:15,608 --> 00:02:16,150 AUDIENCE: OK. 39 00:02:16,150 --> 00:02:21,580 So, I mean, repeating the same action like three times or even more 40 00:02:21,580 --> 00:02:23,095 is not a good habit. 41 00:02:23,095 --> 00:02:24,970 DAVID MALAN: Yeah, I'm just repeating myself. 42 00:02:24,970 --> 00:02:27,340 And honestly, it's not that big a deal. 43 00:02:27,340 --> 00:02:31,780 If we go back to my code here, am I really doing such a bad thing 44 00:02:31,780 --> 00:02:34,180 by just printing meow, meow, meow three times? 45 00:02:34,180 --> 00:02:37,250 Not really, but let's consider the logical extension of this. 46 00:02:37,250 --> 00:02:43,510 Suppose I wanted to meow four times or five times or 50 times or 500 times. 47 00:02:43,510 --> 00:02:46,150 Do you really think, even if you've never programmed before, 48 00:02:46,150 --> 00:02:50,350 is the solution to this problem really going to be to hit copy-paste 50 times? 49 00:02:50,350 --> 00:02:51,310 Like probably not. 50 00:02:51,310 --> 00:02:52,840 We can probably do better than that. 51 00:02:52,840 --> 00:02:54,850 And beyond it just being ugly at that point, 52 00:02:54,850 --> 00:02:57,732 having so many lines of identical code, just 53 00:02:57,732 --> 00:02:59,440 imagine if you wanted to change the code. 54 00:02:59,440 --> 00:03:02,607 Maybe I change my mind and I don't want to make a cat, I want to make a dog. 55 00:03:02,607 --> 00:03:04,930 So now it has to say woof, woof, woof multiple times. 56 00:03:04,930 --> 00:03:07,780 Now I have to change that in 50 different places. 57 00:03:07,780 --> 00:03:10,030 And yeah, sure, I could do find and replace, 58 00:03:10,030 --> 00:03:12,070 but come on, like we're programmers now, there's 59 00:03:12,070 --> 00:03:15,080 got to be a better way than just repeating ourselves. 60 00:03:15,080 --> 00:03:18,400 So I bet we can do better than that if we think about a little 61 00:03:18,400 --> 00:03:22,960 harder how we go about structuring this program. 62 00:03:22,960 --> 00:03:26,750 And we can do that if we augment our vocabulary just a little bit. 63 00:03:26,750 --> 00:03:28,870 It turns out in Python, and in other languages, 64 00:03:28,870 --> 00:03:31,270 too, there's a keyword called while. 65 00:03:31,270 --> 00:03:34,960 And while is one way that we can express what's called a loop, 66 00:03:34,960 --> 00:03:38,530 a block of code that's going to do something again and again and again-- 67 00:03:38,530 --> 00:03:43,480 0 times, 1 time, 2 times, 50 times, as many times as we want. 68 00:03:43,480 --> 00:03:48,520 But while rather leaves to us the particulars 69 00:03:48,520 --> 00:03:52,010 of how we express ourselves to do something again and again. 70 00:03:52,010 --> 00:03:56,260 So let me go back over to VS Code here and let me propose that I do this. 71 00:03:56,260 --> 00:04:01,765 While is a construct that allows me to ask a question again and again. 72 00:04:01,765 --> 00:04:03,640 And any time we've seen a question, it's been 73 00:04:03,640 --> 00:04:07,180 in the form of a Boolean expression, a question to which the answer is 74 00:04:07,180 --> 00:04:08,900 true or false. 75 00:04:08,900 --> 00:04:10,250 Well, how could I do this? 76 00:04:10,250 --> 00:04:15,340 How could I print out meow three times and ask three times a question 77 00:04:15,340 --> 00:04:18,079 to which the answer is true or false? 78 00:04:18,079 --> 00:04:20,110 Well, what if I did some counting? 79 00:04:20,110 --> 00:04:21,560 Like literally on my fingers. 80 00:04:21,560 --> 00:04:25,360 And if I'm trying to count maybe down from three, I want to meow three times, 81 00:04:25,360 --> 00:04:28,060 I can put three fingers up and I can meow. 82 00:04:28,060 --> 00:04:31,342 And then I can put like one of the fingers down and then meow. 83 00:04:31,342 --> 00:04:33,550 And I can put one of the fingers down and I can meow. 84 00:04:33,550 --> 00:04:34,870 Put one of the fingers down. 85 00:04:34,870 --> 00:04:38,200 And maybe the question I can ask every time I meow 86 00:04:38,200 --> 00:04:40,840 is, do I have any fingers up still? 87 00:04:40,840 --> 00:04:42,370 Do I have any fingers up still? 88 00:04:42,370 --> 00:04:43,662 Do I have any fingers up still? 89 00:04:43,662 --> 00:04:45,490 And if the answer is true, keep going. 90 00:04:45,490 --> 00:04:48,040 If the answer is false, stop. 91 00:04:48,040 --> 00:04:50,710 So how can I translate that to code? 92 00:04:50,710 --> 00:04:53,020 Well, once we've added this while keyword-- 93 00:04:53,020 --> 00:04:57,590 I think we have all the building blocks already, let me propose that I do this. 94 00:04:57,590 --> 00:04:59,860 Let me propose that I give myself a variable. 95 00:04:59,860 --> 00:05:02,740 And I'll call it i for integer, but I could call it anything I want, 96 00:05:02,740 --> 00:05:04,780 and I'm going to initialize it to 3. 97 00:05:04,780 --> 00:05:07,780 Then I'm going to use this new feature of Python, while, 98 00:05:07,780 --> 00:05:12,380 and I'm going to ask a question, the answer to which must be true or false. 99 00:05:12,380 --> 00:05:17,470 And I'm going to say, while i does not equal 0. 100 00:05:17,470 --> 00:05:22,630 So I'm going to ask the question, while i does not equal 0, do the following. 101 00:05:22,630 --> 00:05:24,760 Notice the colon at the end of the line. 102 00:05:24,760 --> 00:05:25,890 Notice my indentation. 103 00:05:25,890 --> 00:05:28,470 And just like with functions, just like with conditionals, 104 00:05:28,470 --> 00:05:34,440 you indent the lines that you only want to execute as part of this other thing. 105 00:05:34,440 --> 00:05:37,920 What do I want to do while i does not equal 0? 106 00:05:37,920 --> 00:05:41,130 Well, I think I just want to meow. 107 00:05:41,130 --> 00:05:44,820 But it's not enough just to write this code. 108 00:05:44,820 --> 00:05:52,380 If I were to very dangerously run Python of cat.py and hit Enter right now, 109 00:05:52,380 --> 00:05:55,560 what might happen on the screen? 110 00:05:55,560 --> 00:05:58,320 Whether you've programmed before or not. 111 00:05:58,320 --> 00:06:01,200 Why is this a very bad thing potentially? 112 00:06:01,200 --> 00:06:05,700 It's not going to break things, but it might lose control of my computer 113 00:06:05,700 --> 00:06:07,270 somehow. 114 00:06:07,270 --> 00:06:08,620 Any thoughts? 115 00:06:08,620 --> 00:06:10,120 Yeah, Timo? 116 00:06:10,120 --> 00:06:11,020 AUDIENCE: Hi. 117 00:06:11,020 --> 00:06:18,790 I think it's going to continue to print out meow since i is always equal to 3 118 00:06:18,790 --> 00:06:20,995 and the while is always true. 119 00:06:20,995 --> 00:06:22,120 DAVID MALAN: Yeah, exactly. 120 00:06:22,120 --> 00:06:26,320 If I'm initializing i to 3-- that is, setting it equal to 3 on line 1, 121 00:06:26,320 --> 00:06:29,440 then I'm asking the question, while i does not equal 0, 122 00:06:29,440 --> 00:06:31,810 and that's going to be true, it does not equal 0, 123 00:06:31,810 --> 00:06:34,240 it obviously equals 3, print meow. 124 00:06:34,240 --> 00:06:38,950 And the way a while loop works is that the Python interpreter just 125 00:06:38,950 --> 00:06:40,480 keeps going back and forth. 126 00:06:40,480 --> 00:06:45,310 It goes from line 1 to line 2, then to line 3, 127 00:06:45,310 --> 00:06:48,490 and then it goes back to line 2 to ask the question again. 128 00:06:48,490 --> 00:06:50,950 If the answer is still true, it goes to line 3. 129 00:06:50,950 --> 00:06:52,420 It then goes back to line 2. 130 00:06:52,420 --> 00:06:55,090 If the answer is still true, it goes back to line 3. 131 00:06:55,090 --> 00:07:00,100 And to Timo's point, if you're never actually changing the value of i, 132 00:07:00,100 --> 00:07:04,450 it's always 3, you're just going to be looping literally forever, 133 00:07:04,450 --> 00:07:07,028 and this is an accidental infinite loop. 134 00:07:07,028 --> 00:07:08,570 So we've got to be smarter than that. 135 00:07:08,570 --> 00:07:09,820 And I'm not going to hit Enter because I don't 136 00:07:09,820 --> 00:07:12,195 want to lose control over my computer here such that it's 137 00:07:12,195 --> 00:07:14,080 printing out meow forever. 138 00:07:14,080 --> 00:07:16,960 Fortunately, if you ever do do that and you find yourself 139 00:07:16,960 --> 00:07:21,940 in an accidental infinite loop, Control-C for cancel or interrupt 140 00:07:21,940 --> 00:07:23,110 is going to be your friend. 141 00:07:23,110 --> 00:07:26,110 If you ever seem to lose control, you don't need to reboot 142 00:07:26,110 --> 00:07:27,520 or turn off the computer. 143 00:07:27,520 --> 00:07:30,430 You can just hit Control-C in your terminal window 144 00:07:30,430 --> 00:07:32,560 and that will likely fix it. 145 00:07:32,560 --> 00:07:35,920 All right, well what do I want to do, then, after meowing each time? 146 00:07:35,920 --> 00:07:39,820 I think what I'd like to do here is maybe something like this. 147 00:07:39,820 --> 00:07:46,750 Let me update i to equal whatever the current value is minus 1 here-- 148 00:07:46,750 --> 00:07:47,530 whoops, sorry. 149 00:07:47,530 --> 00:07:48,820 Minus 1. 150 00:07:48,820 --> 00:07:51,310 So if i on each iteration-- 151 00:07:51,310 --> 00:07:55,090 I'm updating i to be one less, one less, one less, 152 00:07:55,090 --> 00:08:00,610 it should eventually hit 0, at which point the answer to 9.2's question 153 00:08:00,610 --> 00:08:02,540 will now be false. 154 00:08:02,540 --> 00:08:03,770 So let's see if this works. 155 00:08:03,770 --> 00:08:06,790 I'm going to go down to my terminal window and run Python of cat.py, 156 00:08:06,790 --> 00:08:09,700 and I indeed get three meows. 157 00:08:09,700 --> 00:08:10,360 Why? 158 00:08:10,360 --> 00:08:14,230 Because I've wired this up like a machine in software, if you will. 159 00:08:14,230 --> 00:08:17,360 I've set i equal to 3, then I keep asking this question. 160 00:08:17,360 --> 00:08:21,940 But I keep turning the gears, I keep changing the value of the variable 161 00:08:21,940 --> 00:08:25,180 to make sure that ultimately it is actually 162 00:08:25,180 --> 00:08:30,468 being decremented-- that is, decreased by 1 until we eventually hit 0. 163 00:08:30,468 --> 00:08:33,010 Now for those of you who think I'm a little more graphically, 164 00:08:33,010 --> 00:08:35,110 let me pull up one of our usual flow charts. 165 00:08:35,110 --> 00:08:38,610 This is just a representation graphically of the exact same thing. 166 00:08:38,610 --> 00:08:39,610 Notice what's happening. 167 00:08:39,610 --> 00:08:44,020 I first start the program, and then I initialize i to 3, 168 00:08:44,020 --> 00:08:46,300 and then I ask the first of my questions. 169 00:08:46,300 --> 00:08:48,577 Again, the diamonds always represent questions. 170 00:08:48,577 --> 00:08:50,410 And the answer is going to be true or false. 171 00:08:50,410 --> 00:08:52,690 Does i not equal 0? 172 00:08:52,690 --> 00:08:54,190 Well, it doesn't, it equals 3. 173 00:08:54,190 --> 00:08:56,710 So if I follow the true line, I meow. 174 00:08:56,710 --> 00:09:01,690 And then I follow this arrow, and I update i to equal i minus 1. 175 00:09:01,690 --> 00:09:05,200 At this point in the story, i presumably equals 2 mathematically. 176 00:09:05,200 --> 00:09:06,400 I follow the arrow. 177 00:09:06,400 --> 00:09:07,483 And there's the loop. 178 00:09:07,483 --> 00:09:09,400 This is why it's nice to see this graphically, 179 00:09:09,400 --> 00:09:12,770 perhaps because you can literally see the loop back and forth. 180 00:09:12,770 --> 00:09:14,240 Now I ask the question again. 181 00:09:14,240 --> 00:09:16,270 Does 2 not equal 0? 182 00:09:16,270 --> 00:09:20,060 Well, it does not equal 0, it's 2, so we meow again. 183 00:09:20,060 --> 00:09:21,940 We change i from 2 to 1. 184 00:09:21,940 --> 00:09:23,770 Well, does 1 not equal 0? 185 00:09:23,770 --> 00:09:27,490 Well obviously 1 is not 0, so we meow again. 186 00:09:27,490 --> 00:09:30,580 We decrement i again. i is now 0. 187 00:09:30,580 --> 00:09:33,070 Does 0 not equal 0? 188 00:09:33,070 --> 00:09:37,930 No, it equals 0, so the answer is false and we stop. 189 00:09:37,930 --> 00:09:41,260 So there, perhaps more so than any of our flowcharts before, 190 00:09:41,260 --> 00:09:45,295 do you really see the structure of what's happening inside of the program? 191 00:09:45,295 --> 00:09:47,920 And you don't have to get into the habit of making these charts 192 00:09:47,920 --> 00:09:50,830 or creating these charts, but just as a first pass at what's 193 00:09:50,830 --> 00:09:55,010 going on inside of the computer, that's indeed one way to visualize it instead. 194 00:09:55,010 --> 00:09:57,760 Well let me propose that, like always, there's many different ways 195 00:09:57,760 --> 00:09:58,690 to solve this problem. 196 00:09:58,690 --> 00:10:01,023 And suppose you just like to think a little differently. 197 00:10:01,023 --> 00:10:04,700 Maybe you don't like starting at 3 and then counting down to 0. 198 00:10:04,700 --> 00:10:05,200 Why? 199 00:10:05,200 --> 00:10:07,075 Maybe you're just brain doesn't work that way 200 00:10:07,075 --> 00:10:09,100 and you prefer to count up instead of down. 201 00:10:09,100 --> 00:10:10,400 Totally fine. 202 00:10:10,400 --> 00:10:15,700 Let me go ahead and change my code here to set i equal to 1 instead of 3. 203 00:10:15,700 --> 00:10:18,040 And here, let me just change my logic. 204 00:10:18,040 --> 00:10:20,500 Rather than checking for not equal to 0, like maybe 205 00:10:20,500 --> 00:10:23,500 you don't like thinking in terms of not because it's a little confusing, 206 00:10:23,500 --> 00:10:28,720 and it might be, let's just check that i is less than or equal to 3. 207 00:10:28,720 --> 00:10:30,310 So we'll be a little more explicit. 208 00:10:30,310 --> 00:10:34,690 We'll count from 1 up through 3, each time printing meow, 209 00:10:34,690 --> 00:10:36,970 but I'm going to need to change this line here. 210 00:10:36,970 --> 00:10:40,240 Let me see if we can't call on someone to change line for me. 211 00:10:40,240 --> 00:10:47,560 How do I want to change line 4 to be consistent with counting from 1 up 212 00:10:47,560 --> 00:10:52,080 to and through 3? 213 00:10:52,080 --> 00:10:57,465 AUDIENCE: I would be plus 1 every time you meow. 214 00:10:57,465 --> 00:10:58,590 DAVID MALAN: Yeah, exactly. 215 00:10:58,590 --> 00:11:01,800 In this case, we want to add one not subtract 1. 216 00:11:01,800 --> 00:11:05,460 And in fact, if you think about this, this 2 could end very poorly. 217 00:11:05,460 --> 00:11:09,630 If you start counting at 1 and you keep subtracting 1, subtracting 1, 218 00:11:09,630 --> 00:11:11,850 subtracting 1, I think we're going to find ourselves 219 00:11:11,850 --> 00:11:15,780 with the same problem, which is that we're never going to stop because we're 220 00:11:15,780 --> 00:11:19,140 going to keep getting more and more negative as opposed to ever getting up 221 00:11:19,140 --> 00:11:20,160 to the number 3. 222 00:11:20,160 --> 00:11:24,660 So I think you're right, I need to change this to be i equals i plus 1. 223 00:11:24,660 --> 00:11:27,840 And now notice just for clarity, too, the equal sign 224 00:11:27,840 --> 00:11:30,810 is, again, our assignment operator from right to left. 225 00:11:30,810 --> 00:11:33,150 Logically, this might otherwise strike you as strange. 226 00:11:33,150 --> 00:11:35,880 Like how can i equal itself plus 1? 227 00:11:35,880 --> 00:11:39,720 Well, it doesn't until you execute this code from right to left. 228 00:11:39,720 --> 00:11:44,550 You add 1 to i or you subtract 1 from i, and then you update the value of i 229 00:11:44,550 --> 00:11:45,240 on the left. 230 00:11:45,240 --> 00:11:48,400 The assignment copies the value from the right to the left. 231 00:11:48,400 --> 00:11:49,780 Well, how else might I do this? 232 00:11:49,780 --> 00:11:55,110 Well, I will say that most programmers, computer scientists more generally, 233 00:11:55,110 --> 00:11:57,180 tend to start counting from 0. 234 00:11:57,180 --> 00:11:59,640 It's a convention and it actually has upsides even 235 00:11:59,640 --> 00:12:02,440 in Python and other languages where generally speaking, 236 00:12:02,440 --> 00:12:04,600 it's a good thing to start counting from 0 237 00:12:04,600 --> 00:12:07,620 instead of counting like we might in the real world from 1. 238 00:12:07,620 --> 00:12:10,170 Let's go ahead and adopt that convention now. 239 00:12:10,170 --> 00:12:14,400 Let me set i equal to 0, and I need to make a change now. 240 00:12:14,400 --> 00:12:19,560 Notice, if I don't change my logic, this program just became buggy. 241 00:12:19,560 --> 00:12:20,730 The cat has a bug. 242 00:12:20,730 --> 00:12:23,940 It's now meowing four times if I run it as is. 243 00:12:23,940 --> 00:12:27,660 But the easiest fix here would be to change my inequality 244 00:12:27,660 --> 00:12:31,810 to be this, less than instead of less than or equal to. 245 00:12:31,810 --> 00:12:36,480 Now I'm starting at 0, but I'm going up to but not through 3. 246 00:12:36,480 --> 00:12:40,020 And even though this might, of all the things we've seen thus far, 247 00:12:40,020 --> 00:12:44,400 seem maybe the least familiar, most of us might start at 1, 2, then 3, 248 00:12:44,400 --> 00:12:47,220 it's a good habit to get into now, start at 0, 249 00:12:47,220 --> 00:12:52,110 and go up to but not through the value that you care about ultimately, 250 00:12:52,110 --> 00:12:53,510 3 in this case here. 251 00:12:53,510 --> 00:12:55,260 Well, let me tighten things up a bit here. 252 00:12:55,260 --> 00:12:57,630 Not only will this now fix my counting problem, 253 00:12:57,630 --> 00:13:00,330 it now meows 3 times as expected, there's 254 00:13:00,330 --> 00:13:03,240 a more succinct way to express i equals i 255 00:13:03,240 --> 00:13:06,690 plus 1, and this, is because it's such a popular thing to do in code. 256 00:13:06,690 --> 00:13:11,830 You can instead just say i plus equals 1, and that's it. 257 00:13:11,830 --> 00:13:14,250 You don't need to put everything on the right-hand side. 258 00:13:14,250 --> 00:13:19,320 This is a special syntax that says the exact same thing, increment i, 259 00:13:19,320 --> 00:13:21,742 but it does it with a few fewer keystrokes. 260 00:13:21,742 --> 00:13:24,700 It's just a little more pleasant to type, it's a little faster to read, 261 00:13:24,700 --> 00:13:25,830 it's just a convention. 262 00:13:25,830 --> 00:13:29,745 Those of you who have programmed in C, C++, Python-- 263 00:13:29,745 --> 00:13:30,660 no, not Python. 264 00:13:30,660 --> 00:13:36,990 C, C++, Java, JavaScript might have seen plus-plus before or minus-minus. 265 00:13:36,990 --> 00:13:40,080 Sorry, Python doesn't have it, so you cannot use that. 266 00:13:40,080 --> 00:13:44,040 This is as succinct as your line of code might get. 267 00:13:44,040 --> 00:13:44,870 All right. 268 00:13:44,870 --> 00:13:46,620 Let me pause here to see, then, if there's 269 00:13:46,620 --> 00:13:53,400 any questions about these implementations of while loops. 270 00:13:53,400 --> 00:13:55,620 AUDIENCE: Can we use stuff like for loops 271 00:13:55,620 --> 00:14:02,760 which have a certain i-value initialized to it at the start 272 00:14:02,760 --> 00:14:09,300 and it runs from the particular condition you put into the thing 273 00:14:09,300 --> 00:14:12,090 and increment it as you go along? 274 00:14:12,090 --> 00:14:15,700 DAVID MALAN: Short answer, no, you cannot do what you're describing, 275 00:14:15,700 --> 00:14:18,790 but there is another type of for loop that we will soon see. 276 00:14:18,790 --> 00:14:20,520 But let's come to that in just a moment. 277 00:14:20,520 --> 00:14:26,080 Other questions on loops using while here? 278 00:14:26,080 --> 00:14:28,443 AUDIENCE: So I had a question about that flowchart. 279 00:14:28,443 --> 00:14:29,110 DAVID MALAN: OK. 280 00:14:29,110 --> 00:14:30,490 AUDIENCE: There were-- yeah. 281 00:14:30,490 --> 00:14:36,510 There were certain symbols for the certain kind of the statements were-- 282 00:14:36,510 --> 00:14:42,283 are they certainly used for that kind of statement that they-- 283 00:14:42,283 --> 00:14:43,200 DAVID MALAN: They are. 284 00:14:43,200 --> 00:14:44,790 So I deliberate-- 285 00:14:44,790 --> 00:14:47,340 I deliberately use certain types of symbols, certain shapes 286 00:14:47,340 --> 00:14:51,570 here whereby an oval is conventional for start and stop. 287 00:14:51,570 --> 00:14:56,820 I used rectangles for any statement of code, like an assignment or a printing 288 00:14:56,820 --> 00:14:57,630 and so forth. 289 00:14:57,630 --> 00:15:02,040 And I used diamonds to represent questions that you might ask, 290 00:15:02,040 --> 00:15:03,988 conditions as we've seen. 291 00:15:03,988 --> 00:15:06,030 If you're doing this for yourself, if you're just 292 00:15:06,030 --> 00:15:07,950 trying to make sense of your code and writing it down, 293 00:15:07,950 --> 00:15:10,158 you certainly don't need to use these formal symbols, 294 00:15:10,158 --> 00:15:13,367 but I tried to be consistent with some best practices. 295 00:15:13,367 --> 00:15:15,450 And in fact, let me come back to the same picture, 296 00:15:15,450 --> 00:15:17,533 because this was the first version of our picture, 297 00:15:17,533 --> 00:15:19,830 but we've since modified our code a couple of times. 298 00:15:19,830 --> 00:15:22,455 This, recall, was the version where the question we were asking 299 00:15:22,455 --> 00:15:26,340 was i not equal to 0, let me go ahead and just change this code now 300 00:15:26,340 --> 00:15:29,250 to represent the next version we did, which, recall, 301 00:15:29,250 --> 00:15:31,950 changed our logic to start counting from 1, 302 00:15:31,950 --> 00:15:36,060 it changed our question to check as i less than or equal to 3, 303 00:15:36,060 --> 00:15:39,570 but then everything else was the same except for the counting, which 304 00:15:39,570 --> 00:15:41,580 is now plus instead of minus. 305 00:15:41,580 --> 00:15:47,040 And then we refined it a little bit further by counting now from 0 up to 306 00:15:47,040 --> 00:15:48,570 but not through 3. 307 00:15:48,570 --> 00:15:52,170 And we tightened up this code here by just incrementing 1 308 00:15:52,170 --> 00:15:54,220 by using the slightly more succinct syntax. 309 00:15:54,220 --> 00:15:57,120 So at this point, these flowcharts might become less and less useful 310 00:15:57,120 --> 00:16:00,690 for us, because once you've wrapped your mind around the concept 311 00:16:00,690 --> 00:16:03,750 and hopefully the picture helps bring that concept to life, 312 00:16:03,750 --> 00:16:06,600 it certainly fine to focus entirely on the code 313 00:16:06,600 --> 00:16:09,240 and only think about or even draw something like this 314 00:16:09,240 --> 00:16:12,120 if you need to wrap your mind around something more complicated 315 00:16:12,120 --> 00:16:13,200 than you're used to. 316 00:16:13,200 --> 00:16:15,240 Well, let me go ahead, if I may, and propose 317 00:16:15,240 --> 00:16:20,490 that we transition to another approach of types of loops using another 318 00:16:20,490 --> 00:16:22,740 keyword here, namely a for loop. 319 00:16:22,740 --> 00:16:25,050 And this is a word that does exist in other languages, 320 00:16:25,050 --> 00:16:28,290 but doesn't necessarily have as many features as other languages might 321 00:16:28,290 --> 00:16:29,260 use it for. 322 00:16:29,260 --> 00:16:33,300 But there is a different type of loop-- not a while loop, but a for loop. 323 00:16:33,300 --> 00:16:37,620 And a for loop is going to allow us to express ourselves a little differently, 324 00:16:37,620 --> 00:16:40,020 but to do so, I propose that the easiest way 325 00:16:40,020 --> 00:16:43,890 is if we introduce one other idea in Python, which is that of a list. 326 00:16:43,890 --> 00:16:48,120 And here, too, no pun intended, we're adding to the list of data types 327 00:16:48,120 --> 00:16:49,290 that Python supports. 328 00:16:49,290 --> 00:16:51,480 We've seen strs or strings. 329 00:16:51,480 --> 00:16:53,050 Ints or integers. 330 00:16:53,050 --> 00:16:54,780 Floats or floating point values. 331 00:16:54,780 --> 00:16:56,670 Bools or Boolean expressions. 332 00:16:56,670 --> 00:17:00,480 Python also has lists, which is another type of data, 333 00:17:00,480 --> 00:17:02,730 but wonderfully, this one is probably pretty familiar. 334 00:17:02,730 --> 00:17:06,240 A list of things in the real world is a list of things in Python. 335 00:17:06,240 --> 00:17:11,490 It's a way of containing multiple values all in the same place, all 336 00:17:11,490 --> 00:17:12,940 in the same variable. 337 00:17:12,940 --> 00:17:14,319 So what do I mean by this? 338 00:17:14,319 --> 00:17:18,480 Well let me propose that we go back to our VS Code here, 339 00:17:18,480 --> 00:17:22,480 and let me start fresh with my code here and not use a while loop at all, 340 00:17:22,480 --> 00:17:24,690 but let me use this new keyword for. 341 00:17:24,690 --> 00:17:30,363 The way for loop works is that it allows you to iterate over a list of items. 342 00:17:30,363 --> 00:17:31,530 So what does this look like? 343 00:17:31,530 --> 00:17:32,940 It might look like this-- 344 00:17:32,940 --> 00:17:39,030 for i and the following list of items, 0, 1, 2. 345 00:17:39,030 --> 00:17:41,640 This is my starting point, and on each iteration 346 00:17:41,640 --> 00:17:45,450 of this loop-- that is, on each execution of this loop again and again, 347 00:17:45,450 --> 00:17:47,550 I want to print out meow. 348 00:17:47,550 --> 00:17:51,360 Now I'll admit, I kind of like the look of this code already 349 00:17:51,360 --> 00:17:53,580 even though there's some new syntax here, 350 00:17:53,580 --> 00:17:55,770 because it's just shorter than the while loop. 351 00:17:55,770 --> 00:17:58,480 The while loop had multiple lines a moment ago 352 00:17:58,480 --> 00:18:01,320 and it was entirely up to me to decide what i is. 353 00:18:01,320 --> 00:18:04,530 I have to check a condition, I have to increment or decrement i. 354 00:18:04,530 --> 00:18:07,230 Like I was doing a lot of work, relatively speaking, 355 00:18:07,230 --> 00:18:10,710 to make that thing turn, to make that loop going to go. 356 00:18:10,710 --> 00:18:12,720 It was very mechanical in a sense. 357 00:18:12,720 --> 00:18:18,030 You can in your mind's eye maybe see the gears turning as all of these variables 358 00:18:18,030 --> 00:18:21,120 are changing and these questions are being asked. 359 00:18:21,120 --> 00:18:24,450 A for loop simplifies all of that, and it just 360 00:18:24,450 --> 00:18:27,480 says, if you want a variable like i, a number, 361 00:18:27,480 --> 00:18:31,770 and you know in advance how many times want this loop to execute-- three 362 00:18:31,770 --> 00:18:34,380 times, we'll just kind of specify what it 363 00:18:34,380 --> 00:18:37,560 is you want i to take on as values explicitly. 364 00:18:37,560 --> 00:18:41,940 In this loop, i will be automatically initialized by Python to be 0, 365 00:18:41,940 --> 00:18:43,530 then meow will be printed. 366 00:18:43,530 --> 00:18:48,870 Then Python would automatically update i to equal 1, then meow will be printed. 367 00:18:48,870 --> 00:18:53,520 Then Python will automatically update i to be 2 and meow will be printed. 368 00:18:53,520 --> 00:18:57,270 And because that's it for the values in that list, Python will stop 369 00:18:57,270 --> 00:19:00,090 and it will only meow a total of three times. 370 00:19:00,090 --> 00:19:01,170 What is the list? 371 00:19:01,170 --> 00:19:05,130 The list in this program is exactly that, 0, comma, 1, comma, 2, 372 00:19:05,130 --> 00:19:07,200 and notice the square brackets. 373 00:19:07,200 --> 00:19:11,350 Those aren't parentheses, those are square brackets that represent a list. 374 00:19:11,350 --> 00:19:15,540 That's how visually as the programmer-- that's how Python knows as the language 375 00:19:15,540 --> 00:19:18,460 that you intend for that to be a list. 376 00:19:18,460 --> 00:19:23,490 So let me go ahead and run this Python of cat.py, and it works just the same. 377 00:19:23,490 --> 00:19:24,660 But it's only two lines. 378 00:19:24,660 --> 00:19:28,330 It's pretty readable once you have familiarity with that construct, 379 00:19:28,330 --> 00:19:33,970 but to my constant point about correctness not necessarily 380 00:19:33,970 --> 00:19:38,800 being the same as design, in what sense is this program perhaps 381 00:19:38,800 --> 00:19:40,150 poorly designed? 382 00:19:40,150 --> 00:19:41,140 It seems to work. 383 00:19:41,140 --> 00:19:45,790 It meows three times, but why might this not 384 00:19:45,790 --> 00:19:48,130 be the best way to solve this problem? 385 00:19:48,130 --> 00:19:51,190 Even if you've never programmed before, again, 386 00:19:51,190 --> 00:19:54,310 think about corner cases, things that may or may not happen. 387 00:19:54,310 --> 00:19:59,168 Think about extreme cases that really test the quality of this code. 388 00:19:59,168 --> 00:19:59,710 AUDIENCE: OK. 389 00:19:59,710 --> 00:20:06,880 I think that because we are saying 0, 1, 2 3 times. 390 00:20:06,880 --> 00:20:11,030 And then if you want to take a million, you say 1, 2, 3. 391 00:20:11,030 --> 00:20:12,967 DAVID MALAN: Yeah, exactly. 392 00:20:12,967 --> 00:20:15,550 And that's what I mean about thinking about the extreme cases. 393 00:20:15,550 --> 00:20:18,430 If you're trying to decide for yourself if your own code is good 394 00:20:18,430 --> 00:20:22,120 or someone else's code is good, it might look so at first glance, 395 00:20:22,120 --> 00:20:23,530 but think about the extreme. 396 00:20:23,530 --> 00:20:26,410 Well, what if it's not three things, it's a million things? 397 00:20:26,410 --> 00:20:31,180 I mean, are you really going to write out 0 through a million or 0 398 00:20:31,180 --> 00:20:33,160 through 9-- 399 00:20:33,160 --> 00:20:38,090 999,999? 400 00:20:38,090 --> 00:20:40,840 Like no, you're not going to write that many numbers on the screen 401 00:20:40,840 --> 00:20:42,500 there's got to be a better way. 402 00:20:42,500 --> 00:20:45,100 So let's do the better way from the get-go 403 00:20:45,100 --> 00:20:47,980 rather than set the stage for doing something poorly. 404 00:20:47,980 --> 00:20:52,090 And the one way we can solve this problem to improve the design 405 00:20:52,090 --> 00:20:56,950 is don't just manually specify the list of values, use a function, 406 00:20:56,950 --> 00:20:59,140 someone else's function that comes with Python 407 00:20:59,140 --> 00:21:00,850 that gives you the list you want. 408 00:21:00,850 --> 00:21:02,680 And the easiest way to do that in Python is 409 00:21:02,680 --> 00:21:07,480 to use a function called range that returns to a range of values. 410 00:21:07,480 --> 00:21:09,940 It expects as input at least one argument, 411 00:21:09,940 --> 00:21:14,170 and that number is going to be the number of values you want back. 412 00:21:14,170 --> 00:21:18,620 Those values are going to start at 0 and go to 1, to 2, and so forth, 413 00:21:18,620 --> 00:21:22,910 but they will go up two but not through the number you specify. 414 00:21:22,910 --> 00:21:26,200 So by specifying range 3, you're essentially 415 00:21:26,200 --> 00:21:29,350 being handed back 1, 2, 3 values. 416 00:21:29,350 --> 00:21:33,730 And by default, those values are 0, 1, and 2, and that's it. 417 00:21:33,730 --> 00:21:37,240 But what's brilliant about this is that now, to Hope's point, if I do 418 00:21:37,240 --> 00:21:38,950 want to meow a million times-- 419 00:21:38,950 --> 00:21:44,320 I mean, that is an angry cat, I can now do a million by just typing a million. 420 00:21:44,320 --> 00:21:48,910 I don't have to literally type 0, comma, 1, comma, 2, comma, 3, comma, 421 00:21:48,910 --> 00:21:53,620 4, all the way up to 999,999, I just do this. 422 00:21:53,620 --> 00:21:57,140 So that's got to be a better way long-term. 423 00:21:57,140 --> 00:21:59,080 So that's indeed one improvement we can indeed 424 00:21:59,080 --> 00:22:03,050 make here still using a for loop, but now using this range function. 425 00:22:03,050 --> 00:22:05,470 And just to show you something else that's Pythonic-- 426 00:22:05,470 --> 00:22:07,690 this is not strictly necessary, but it's commonly 427 00:22:07,690 --> 00:22:11,560 done, there's a minor improvement we can make here, 428 00:22:11,560 --> 00:22:14,180 even if we're just meowing three times. 429 00:22:14,180 --> 00:22:20,710 And notice that even though I'm defining a variable i, I'm not ever using it. 430 00:22:20,710 --> 00:22:24,700 And it's kind of necessary logically, because Python, presumably, 431 00:22:24,700 --> 00:22:26,620 has to use something for counting. 432 00:22:26,620 --> 00:22:28,960 It has to know what it's iterating over. 433 00:22:28,960 --> 00:22:30,970 But there's this convention in Python where 434 00:22:30,970 --> 00:22:35,320 if you need a variable, just because the programming feature requires 435 00:22:35,320 --> 00:22:38,890 it to do some kind of counting or automatic updating, but you, the human, 436 00:22:38,890 --> 00:22:42,550 don't care about its value, a Pythonic improvement here 437 00:22:42,550 --> 00:22:45,520 would be to name that variable a single underscore. 438 00:22:45,520 --> 00:22:48,280 Just because it's not required, it doesn't 439 00:22:48,280 --> 00:22:50,410 change the correctness of the program, but it 440 00:22:50,410 --> 00:22:54,190 signals to yourself later, it signals to colleagues or teachers that 441 00:22:54,190 --> 00:22:57,207 are looking at your code, too, that yes, it's a variable, 442 00:22:57,207 --> 00:23:00,040 but you don't care about its name because you're not using it later, 443 00:23:00,040 --> 00:23:04,840 it's just necessary in order to use this feature, this loop in this case here. 444 00:23:04,840 --> 00:23:09,190 So just a minor improvement or change there. 445 00:23:09,190 --> 00:23:13,510 But to really gets you intrigued by what's possible in Python, 446 00:23:13,510 --> 00:23:15,140 let's take this one step further. 447 00:23:15,140 --> 00:23:19,780 So if we really want to be Pythonic, this one, if you've programmed before, 448 00:23:19,780 --> 00:23:22,310 is kind of going to blow your mind, so to speak, 449 00:23:22,310 --> 00:23:27,820 whereby if I want the cat to meow three times, what if I actually do this? 450 00:23:27,820 --> 00:23:34,350 print, open parenthesis, quote-unquote, meow times 3. 451 00:23:34,350 --> 00:23:37,620 You have to be kind of a geek to think this is cool, but this is kind of cool. 452 00:23:37,620 --> 00:23:40,620 So you can literally just print what you want, 453 00:23:40,620 --> 00:23:44,070 multiply it by the number of times that you want it, 454 00:23:44,070 --> 00:23:47,760 and you will get back exactly that result. 455 00:23:47,760 --> 00:23:50,763 Now I've kind of made a mistake here. 456 00:23:50,763 --> 00:23:51,930 So let's see what this does. 457 00:23:51,930 --> 00:23:56,730 It's not quite as beautiful as this code might look to you-- to some of you, 458 00:23:56,730 --> 00:23:57,240 to me. 459 00:23:57,240 --> 00:24:00,300 Let me run Python of cat.py, Enter. 460 00:24:00,300 --> 00:24:02,820 OK, it's a really like hungry cat or something. 461 00:24:02,820 --> 00:24:04,350 It's meowing really fast. 462 00:24:04,350 --> 00:24:06,830 But I can fix this, I bet. 463 00:24:06,830 --> 00:24:10,010 Let's think about now some of the basic building blocks we've discussed. 464 00:24:10,010 --> 00:24:13,160 The problem is clearly that literally meow, meow, 465 00:24:13,160 --> 00:24:16,460 meow is being repeated three times, but it's not as pretty as I want it. 466 00:24:16,460 --> 00:24:19,910 I want it to be meow, meow, meow on separate lines. 467 00:24:19,910 --> 00:24:22,850 What might be a possible solution here while still 468 00:24:22,850 --> 00:24:26,780 using this multiplication operator? 469 00:24:26,780 --> 00:24:27,560 And think back. 470 00:24:27,560 --> 00:24:30,170 We've used plus to concatenate strings. 471 00:24:30,170 --> 00:24:33,980 You can apparently use multiplication to concatenate strings, but more than once 472 00:24:33,980 --> 00:24:35,180 again and again and again. 473 00:24:35,180 --> 00:24:37,580 How could I clean this up without reverting 474 00:24:37,580 --> 00:24:42,240 to my for loop or my while loop and still use multiplication in this way? 475 00:24:42,240 --> 00:24:45,975 AUDIENCE: We can use the escape sequence which would be backslash n. 476 00:24:45,975 --> 00:24:46,850 DAVID MALAN: Amazing. 477 00:24:46,850 --> 00:24:47,350 Yes. 478 00:24:47,350 --> 00:24:50,750 Think back to backslash n, which is the way you as the programmer 479 00:24:50,750 --> 00:24:52,970 can express a new line in code. 480 00:24:52,970 --> 00:24:57,560 And I think, if I take your advice, I put a backslash in there inside 481 00:24:57,560 --> 00:25:02,390 of my quotes, so that at the end of every M-E-O-W, there's a new line, 482 00:25:02,390 --> 00:25:03,470 let's see how this looks. 483 00:25:03,470 --> 00:25:06,650 Let me clear my screen and run Python of cat.py. 484 00:25:06,650 --> 00:25:08,270 OK, so close. 485 00:25:08,270 --> 00:25:09,030 I like this. 486 00:25:09,030 --> 00:25:10,490 Let me call on someone else. 487 00:25:10,490 --> 00:25:13,670 The only thing I don't like-- and I know I'm being really nitpicky now-- 488 00:25:13,670 --> 00:25:15,840 is that it's meow, meow, meow on separate lines, 489 00:25:15,840 --> 00:25:20,300 but there's this extra blank line, which I'm just not loving aesthetically. 490 00:25:20,300 --> 00:25:25,430 AUDIENCE: I think we can make n equal to column-- 491 00:25:25,430 --> 00:25:27,410 column, not-- like a slash n. 492 00:25:27,410 --> 00:25:28,160 DAVID MALAN: Yeah. 493 00:25:28,160 --> 00:25:31,010 So here, too, like all of these things we've seen in past weeks 494 00:25:31,010 --> 00:25:32,630 are kind of coming together. 495 00:25:32,630 --> 00:25:37,010 Recall that the print function lets you control what the line ending is. 496 00:25:37,010 --> 00:25:39,570 By default, it's backslash n itself. 497 00:25:39,570 --> 00:25:41,540 Which is why at the very end of this print, 498 00:25:41,540 --> 00:25:44,300 the cursor is being moved again to the next line. 499 00:25:44,300 --> 00:25:46,260 Well, we need to just override that. 500 00:25:46,260 --> 00:25:50,420 So let me go into my code here and let me change this to comma n 501 00:25:50,420 --> 00:25:54,890 equals quote-unquote so that it's no longer the default backslash n, 502 00:25:54,890 --> 00:25:59,150 it's instead now going to be nothing whatsoever. 503 00:25:59,150 --> 00:26:03,890 That should eliminate, then, hopefully that additional blank line. 504 00:26:03,890 --> 00:26:07,220 So let me run this one last time here, Python of cat.py, Enter, 505 00:26:07,220 --> 00:26:08,640 and there we have it. 506 00:26:08,640 --> 00:26:12,200 So now, at least as programming goes, it's 507 00:26:12,200 --> 00:26:15,530 kind of cool that I can distill this into a short line 508 00:26:15,530 --> 00:26:17,120 and express myself all at once. 509 00:26:17,120 --> 00:26:19,520 Now to be fair, it's a little less readable. 510 00:26:19,520 --> 00:26:21,950 Like now I've got backslash n, I've got times 3, 511 00:26:21,950 --> 00:26:23,390 I've got n equals quote-unquote. 512 00:26:23,390 --> 00:26:25,400 So you don't have to do things this way. 513 00:26:25,400 --> 00:26:28,440 My previous approach with a for loop, totally fine. 514 00:26:28,440 --> 00:26:31,940 My previous approach with a while loop, totally fine, and in some sense, 515 00:26:31,940 --> 00:26:33,740 perfectly well-designed. 516 00:26:33,740 --> 00:26:36,600 But this is just yet another way to do it, 517 00:26:36,600 --> 00:26:40,250 but it's not a good thing if you or your teacher, your colleague, your friend 518 00:26:40,250 --> 00:26:42,410 are going to struggle to read your own code. 519 00:26:42,410 --> 00:26:47,870 But this is a feature of Python that some languages do not, in fact, have. 520 00:26:47,870 --> 00:26:51,110 All right, well let me propose that things get more interesting still 521 00:26:51,110 --> 00:26:53,690 if we're not just meowing three times only, 522 00:26:53,690 --> 00:26:56,180 but we're meowing some variable number of times. 523 00:26:56,180 --> 00:26:58,940 Let's ask the user how many times this cat should meow. 524 00:26:58,940 --> 00:27:03,540 So let me clear the screen here, and let me figure out, well, 525 00:27:03,540 --> 00:27:05,760 how do I get a number from the user? 526 00:27:05,760 --> 00:27:08,670 The catch here is that if I want the user to give me a number, 527 00:27:08,670 --> 00:27:12,290 I'm not doing math, per se, I'm meowing, and therefore, the user 528 00:27:12,290 --> 00:27:14,630 has to give me a positive value. 529 00:27:14,630 --> 00:27:17,100 The user has to give me a positive value. 530 00:27:17,100 --> 00:27:18,860 So how can I insist on this? 531 00:27:18,860 --> 00:27:25,800 Well, if I just do this, n equals int of input, what's n, question mark? 532 00:27:25,800 --> 00:27:28,040 Well, I want to check like-- 533 00:27:28,040 --> 00:27:32,150 I could say if n is less than 0-- 534 00:27:32,150 --> 00:27:34,430 like if it's negative, well I could do this. 535 00:27:34,430 --> 00:27:35,870 Well, then ask again. 536 00:27:35,870 --> 00:27:40,370 Int, input, what's n, question mark? 537 00:27:40,370 --> 00:27:43,312 OK, well what if the user still doesn't give me a positive number? 538 00:27:43,312 --> 00:27:45,770 What if being really difficult they're not paying attention 539 00:27:45,770 --> 00:27:47,395 and they typed in two negative numbers? 540 00:27:47,395 --> 00:27:53,000 Well, if n is less than 0, well, let's do it again. n equals-- 541 00:27:53,000 --> 00:27:54,170 this does not end well. 542 00:27:54,170 --> 00:27:58,070 You can't infinitely many times keep checking, is it negative, 543 00:27:58,070 --> 00:27:59,630 is it negative, or is it negative? 544 00:27:59,630 --> 00:28:01,700 The program would never be done written. 545 00:28:01,700 --> 00:28:05,010 So we can do this I think better maybe with a loop. 546 00:28:05,010 --> 00:28:06,200 So let me propose this. 547 00:28:06,200 --> 00:28:09,020 A very common paradigm in Python, when you 548 00:28:09,020 --> 00:28:14,000 want to get user input that matches a certain expectation you have, 549 00:28:14,000 --> 00:28:17,570 that it's all positive, that it's all negative, or just something like that, 550 00:28:17,570 --> 00:28:20,840 you just immediately say while true. 551 00:28:20,840 --> 00:28:24,380 You deliberately, and a little dangerously but a very conventionally, 552 00:28:24,380 --> 00:28:25,962 induce an infinite loop. 553 00:28:25,962 --> 00:28:27,170 Now what is an infinite loop? 554 00:28:27,170 --> 00:28:28,550 It's just one that goes forever. 555 00:28:28,550 --> 00:28:31,430 And we've seen how that can happen accidentally mathematically. 556 00:28:31,430 --> 00:28:34,700 It's absolutely going to happen when you say while true. 557 00:28:34,700 --> 00:28:35,240 Why? 558 00:28:35,240 --> 00:28:39,180 Well, the answer to the true question is always true. 559 00:28:39,180 --> 00:28:41,570 So this is a way of deliberately inducing a loop that 560 00:28:41,570 --> 00:28:43,470 by default is going to go forever. 561 00:28:43,470 --> 00:28:46,940 So we're going to need a way of breaking out of this loop when 562 00:28:46,940 --> 00:28:48,350 we have the number we want. 563 00:28:48,350 --> 00:28:50,600 The convention, though inside of this otherwise 564 00:28:50,600 --> 00:28:52,970 an infinite loop is to ask the question you care about, 565 00:28:52,970 --> 00:28:55,760 like give me an int by prompting the user for input. 566 00:28:55,760 --> 00:28:57,800 Like what's n, question mark? 567 00:28:57,800 --> 00:28:59,330 And then just ask your question. 568 00:28:59,330 --> 00:29:04,580 So if n is less than 0, then I think we want Python to just continue 569 00:29:04,580 --> 00:29:05,910 to prompt the user again. 570 00:29:05,910 --> 00:29:09,760 That is, we want the code to stay in the loop, recall the input function, 571 00:29:09,760 --> 00:29:11,760 and hope that the user gives us a better answer. 572 00:29:11,760 --> 00:29:14,730 If this time around it's less than 0, so let's just literally 573 00:29:14,730 --> 00:29:16,980 use Python's keyword continue, which says 574 00:29:16,980 --> 00:29:20,100 just that-- continue to stay within this loop. 575 00:29:20,100 --> 00:29:24,000 Else, if it's not less than 0, let's go ahead and just break out 576 00:29:24,000 --> 00:29:27,120 of the loop altogether using another keyword in Python, break. 577 00:29:27,120 --> 00:29:31,140 Break will break you out of the most recently begun loop in this case 578 00:29:31,140 --> 00:29:34,080 if it's not the case that n is less than 0. 579 00:29:34,080 --> 00:29:38,310 So this will work, and it will allow us to get a value that 0 or greater 580 00:29:38,310 --> 00:29:41,340 from the user, but I think we can tighten it up further so as to not 581 00:29:41,340 --> 00:29:43,500 bother having an if, and, and else. 582 00:29:43,500 --> 00:29:49,227 Why don't we instead just say, if n is greater than 0, go ahead and break? 583 00:29:49,227 --> 00:29:51,060 In fact, it's not that interesting a program 584 00:29:51,060 --> 00:29:52,830 if we even allow the user to type in 0. 585 00:29:52,830 --> 00:29:56,430 So let's wait until they give us an integer that is greater than 0 586 00:29:56,430 --> 00:29:59,040 and then break out of this loop. 587 00:29:59,040 --> 00:30:00,960 And what can I now do down here? 588 00:30:00,960 --> 00:30:07,260 For i in range of whatever that value n is, print meow. 589 00:30:07,260 --> 00:30:10,340 And honestly, I don't need i here, so let me come back to that principle 590 00:30:10,340 --> 00:30:10,840 before. 591 00:30:10,840 --> 00:30:12,590 And let me just change it to an underscore 592 00:30:12,590 --> 00:30:14,110 just to be Pythonic, if you will. 593 00:30:14,110 --> 00:30:15,360 So what's going on? 594 00:30:15,360 --> 00:30:20,130 Lines 1 through 4 deliberately implement an infinite loop 595 00:30:20,130 --> 00:30:23,280 that otherwise by default is going to go forever. 596 00:30:23,280 --> 00:30:26,370 But I'm asking a question, inside of that loop, 597 00:30:26,370 --> 00:30:30,450 after getting an int from the user on line 2, I'm then checking, 598 00:30:30,450 --> 00:30:32,310 is it greater than 0? 599 00:30:32,310 --> 00:30:33,570 Or is it 0? 600 00:30:33,570 --> 00:30:34,220 Is it negative? 601 00:30:34,220 --> 00:30:35,970 None of which makes sense for meowing cat. 602 00:30:35,970 --> 00:30:38,380 Like I want the cat to meow at least one time. 603 00:30:38,380 --> 00:30:41,220 So if it is greater than 0, break. 604 00:30:41,220 --> 00:30:45,030 And this break statement, even though it's indented, indented twice, 605 00:30:45,030 --> 00:30:50,140 has the effect of breaking out of the most recently begun while loop. 606 00:30:50,140 --> 00:30:53,670 So once the user gives you a positive value, 607 00:30:53,670 --> 00:30:58,650 then we get to line 6, at which point we meow that many times because 608 00:30:58,650 --> 00:30:59,850 of line 6 and 7. 609 00:30:59,850 --> 00:31:03,960 So if I run this now Python of cat.py, Enter, well, what's n? 610 00:31:03,960 --> 00:31:06,895 Let's start with 3 where we began, meow, meow, meow. 611 00:31:06,895 --> 00:31:10,020 Well this time, let me go ahead and increase the size of my terminal window 612 00:31:10,020 --> 00:31:11,100 just temporarily. 613 00:31:11,100 --> 00:31:16,140 Let me run Python of cat.py, let me do it 10 times, meow 10 times now 614 00:31:16,140 --> 00:31:17,520 appears on the screen. 615 00:31:17,520 --> 00:31:20,640 And the takeaways here are not just that we can meow 10 times 616 00:31:20,640 --> 00:31:22,890 or do something again and again, but this 617 00:31:22,890 --> 00:31:26,880 is a very common paradigm in Python when you want to do something again 618 00:31:26,880 --> 00:31:31,320 and again and again, but only until the user actually gives you 619 00:31:31,320 --> 00:31:34,230 a value that you care about here. 620 00:31:34,230 --> 00:31:36,540 And let me propose actually now that we practice 621 00:31:36,540 --> 00:31:41,830 a little more what we've been preaching, especially when it comes to, say-- 622 00:31:41,830 --> 00:31:45,075 especially when it comes to say writing your own functions. 623 00:31:45,075 --> 00:31:46,950 Now that I'm doing all this meowing, it might 624 00:31:46,950 --> 00:31:50,970 be nice to actually have a meow function that the inventors of Python 625 00:31:50,970 --> 00:31:52,680 didn't envision, so let me do this. 626 00:31:52,680 --> 00:31:56,050 Let me actually get rid of all this code and let me go ahead and do this. 627 00:31:56,050 --> 00:31:59,950 Let me go ahead and say define a main function, as I've done before, 628 00:31:59,950 --> 00:32:02,400 and let me just blindly call meow 3. 629 00:32:02,400 --> 00:32:05,910 Meow doesn't exist yet, but when it does, that'll be great. 630 00:32:05,910 --> 00:32:08,640 So let me go ahead now and define meow. 631 00:32:08,640 --> 00:32:11,850 So am I meow function should take as input 632 00:32:11,850 --> 00:32:16,350 a parameter called n or anything I want, and this part's pretty easy now. 633 00:32:16,350 --> 00:32:17,880 How do you meow n times? 634 00:32:17,880 --> 00:32:22,470 Well, for underscore n, the range of n, go ahead and just print meow. 635 00:32:22,470 --> 00:32:24,780 So same code as before, nothing new here, 636 00:32:24,780 --> 00:32:28,470 I'm just putting that logic inside of a meow function 637 00:32:28,470 --> 00:32:30,810 that's going to have this side effect of printing meow. 638 00:32:30,810 --> 00:32:34,620 And now, as before, let me go down here and let me make sure I call main. 639 00:32:34,620 --> 00:32:39,420 And if I now run this code, Python of cat.py, meow, meow, meow. 640 00:32:39,420 --> 00:32:42,960 It's always going to do three because I've hardcoded to 3. 641 00:32:42,960 --> 00:32:44,730 Well, let's make one improvement here. 642 00:32:44,730 --> 00:32:48,720 Let me go ahead now and maybe do this. 643 00:32:48,720 --> 00:32:50,350 Let me ask the user for a number. 644 00:32:50,350 --> 00:32:54,700 So let's say something like this, number equals get number. 645 00:32:54,700 --> 00:32:55,200 All right. 646 00:32:55,200 --> 00:32:57,210 Unfortunately, there is no function in Python 647 00:32:57,210 --> 00:32:59,940 called get number that gets a positive number from the user, 648 00:32:59,940 --> 00:33:01,080 but I can invent that. 649 00:33:01,080 --> 00:33:05,070 So define get number, open paren, close paren. 650 00:33:05,070 --> 00:33:07,260 And then inside of this function, let me do this. 651 00:33:07,260 --> 00:33:11,160 While true, go ahead and get a number from the user, 652 00:33:11,160 --> 00:33:14,730 converting it to an int asking them, what's n, question mark? 653 00:33:14,730 --> 00:33:19,260 And then if n is what I want, it's a greater than 0 value, 654 00:33:19,260 --> 00:33:24,710 a positive number, I don't want to break this time necessarily, 655 00:33:24,710 --> 00:33:26,000 although I could. 656 00:33:26,000 --> 00:33:30,750 I instead want to return the value so I can actually do this instead. 657 00:33:30,750 --> 00:33:32,600 And this, too, is a feature of Python. 658 00:33:32,600 --> 00:33:35,690 This ability not to just break out of a block of code, 659 00:33:35,690 --> 00:33:38,750 but also to return a value in code. 660 00:33:38,750 --> 00:33:42,590 To actually return a value gives you the ability, ultimately, 661 00:33:42,590 --> 00:33:47,030 to return explicitly a value so that your function has not just a side 662 00:33:47,030 --> 00:33:51,650 effect, necessarily, but it actually hands back, just like input does, 663 00:33:51,650 --> 00:33:56,220 just like int does, just like float does, an actual value to the user. 664 00:33:56,220 --> 00:33:58,790 Now to be clear, I don't have to return n here. 665 00:33:58,790 --> 00:34:02,330 I can still break out of the loop as I've done in the past with code 666 00:34:02,330 --> 00:34:06,860 like this, but then after the loop, I still have to return. 667 00:34:06,860 --> 00:34:10,969 And so what's happening here is that if you use break to get out of the loop, 668 00:34:10,969 --> 00:34:13,730 but you need to hand back a value from a function, 669 00:34:13,730 --> 00:34:15,980 you still have to use the return keyword now 670 00:34:15,980 --> 00:34:20,389 explicitly either in the loop as I did or now outside of the loop 671 00:34:20,389 --> 00:34:24,110 but still inside of the function. 672 00:34:24,110 --> 00:34:26,420 The last thing I'm going to do here now is change 673 00:34:26,420 --> 00:34:28,969 that 3, which we hardcoded earlier, to actually 674 00:34:28,969 --> 00:34:31,590 be the value of the variable we've gotten from the user 675 00:34:31,590 --> 00:34:36,380 so that now down here, if I run Python of cat.py, Enter, what's n? 676 00:34:36,380 --> 00:34:40,219 I can type in 3, I get my three meows, or if I only want one, 677 00:34:40,219 --> 00:34:43,020 I now get one meow instead. 678 00:34:43,020 --> 00:34:43,520 All right. 679 00:34:43,520 --> 00:34:48,230 So if we now have this ability to do things again and again in these loops, 680 00:34:48,230 --> 00:34:51,800 let's see if we can't solve some other problems via which 681 00:34:51,800 --> 00:34:55,894 to express ourselves cyclically, but get back some interesting answers as well. 682 00:34:55,894 --> 00:34:58,898 And let me propose, for instance, that we look 683 00:34:58,898 --> 00:35:00,440 a little more closely at these lists. 684 00:35:00,440 --> 00:35:03,107 It turns out that in Python, and really, in programs in general, 685 00:35:03,107 --> 00:35:05,600 it's useful to have a list of values, because we're 686 00:35:05,600 --> 00:35:10,160 going to be able to work with more and more data, larger and larger data sets. 687 00:35:10,160 --> 00:35:12,530 So let me propose that we come back to VS Code here 688 00:35:12,530 --> 00:35:15,620 and let's do something that's perhaps a little familiar to some folks, 689 00:35:15,620 --> 00:35:17,030 the world of Hogwarts. 690 00:35:17,030 --> 00:35:19,850 And let me go ahead and code up a file called Hogwarts, 691 00:35:19,850 --> 00:35:23,840 and let's see if we can't have a list of students at Hogwarts here. 692 00:35:23,840 --> 00:35:26,270 So I have a new tab called hogwarts.py. 693 00:35:26,270 --> 00:35:30,710 and let me go ahead and propose that I just define in this program 694 00:35:30,710 --> 00:35:32,780 a list of students whose names I know in advance. 695 00:35:32,780 --> 00:35:34,572 So I'm not going to get user input for now. 696 00:35:34,572 --> 00:35:37,250 I'm just going to know from the get-go that the three 697 00:35:37,250 --> 00:35:39,110 students I want to consider are these. 698 00:35:39,110 --> 00:35:41,030 Our variable is going to be called students. 699 00:35:41,030 --> 00:35:44,540 It's going to equal, as I've done in the past, a square bracket, which 700 00:35:44,540 --> 00:35:46,100 means, hey, here comes a list. 701 00:35:46,100 --> 00:35:49,520 And those values are going to be Hermione in quotes, because it's 702 00:35:49,520 --> 00:35:53,980 a string; Harry in quotes, because it's a string; and then Ron in quotes, 703 00:35:53,980 --> 00:35:55,230 because it's a string as well. 704 00:35:55,230 --> 00:35:57,800 So this is a list of length 3. 705 00:35:57,800 --> 00:36:00,500 It's similar in spirit to my list of length 3 earlier, 706 00:36:00,500 --> 00:36:02,960 but that had 3 ints, 0, 1, 2. 707 00:36:02,960 --> 00:36:06,020 Now I have a list of three strings instead. 708 00:36:06,020 --> 00:36:08,940 And this isn't very useful at the moment, 709 00:36:08,940 --> 00:36:11,600 but let me just do something as a check for myself. 710 00:36:11,600 --> 00:36:14,510 Let me print out each of these students. 711 00:36:14,510 --> 00:36:19,760 Well wait a minute, how do I print the contents of a list? 712 00:36:19,760 --> 00:36:22,610 Well, in the past, when we've printed a variable, 713 00:36:22,610 --> 00:36:24,900 we've just printed out the name of the variable. 714 00:36:24,900 --> 00:36:28,970 But I don't want to print out all of Hermione and Harry and Ron all at once. 715 00:36:28,970 --> 00:36:33,350 Maybe I want to print out Hermione first, then Harry, then Ron. 716 00:36:33,350 --> 00:36:36,050 So I need a way to express more precisely which 717 00:36:36,050 --> 00:36:37,790 value do I want from this list? 718 00:36:37,790 --> 00:36:42,590 And the way you do this in Python is you use square brackets in another way. 719 00:36:42,590 --> 00:36:45,890 If you have a variable-- in this case, called students, 720 00:36:45,890 --> 00:36:49,850 and you want to go inside of that variable and get a specific value-- 721 00:36:49,850 --> 00:36:52,940 that is to say, you want to index into the list, 722 00:36:52,940 --> 00:36:57,500 you use square brackets this way using numbers inside of the square brackets. 723 00:36:57,500 --> 00:37:02,570 And here's where we see that it is useful to think and count in terms of 0 724 00:37:02,570 --> 00:37:04,280 on up instead of 1 on up. 725 00:37:04,280 --> 00:37:08,120 These lists in Python are, shall we say, zero-indexed. 726 00:37:08,120 --> 00:37:13,700 The first item in a list is at location 0, the second item in a Python list 727 00:37:13,700 --> 00:37:16,760 is that location 1, and the third is that location 2. 728 00:37:16,760 --> 00:37:19,940 So you're always kind of off by one mentally, but you get used to it, 729 00:37:19,940 --> 00:37:22,275 if you've never programmed before, over time. 730 00:37:22,275 --> 00:37:23,900 So let me print out all three students. 731 00:37:23,900 --> 00:37:27,410 So let me print out students bracket 0, then students bracket 1. 732 00:37:27,410 --> 00:37:30,290 Then lastly, let me print students bracket 2, 733 00:37:30,290 --> 00:37:32,078 and this is my third and final line. 734 00:37:32,078 --> 00:37:35,120 And of course, if I run this code, it probably does what you would guess. 735 00:37:35,120 --> 00:37:39,500 If I run Python of hogwarts.py, there's Hermione, Harry, and Ron 736 00:37:39,500 --> 00:37:41,450 each on their own lines there. 737 00:37:41,450 --> 00:37:43,443 But there's got to be a better way, especially 738 00:37:43,443 --> 00:37:45,860 if I don't know in advance who's going to be in this list, 739 00:37:45,860 --> 00:37:48,230 if next year there's some new students at Hogwarts, 740 00:37:48,230 --> 00:37:50,930 we can use a loop to do something automatically 741 00:37:50,930 --> 00:37:54,590 without having to manually type out 0 and then 1 and 2. 742 00:37:54,590 --> 00:37:57,110 Well, here's another feature of Python. 743 00:37:57,110 --> 00:38:01,310 You can use a for loop not just to count from 0 to 1 to 2, 744 00:38:01,310 --> 00:38:03,870 you can use Python to just iterate over anything. 745 00:38:03,870 --> 00:38:05,420 Not just numbers, but strings. 746 00:38:05,420 --> 00:38:07,100 So I could actually do this. 747 00:38:07,100 --> 00:38:13,460 For student in students, colon, and then indented underneath that, 748 00:38:13,460 --> 00:38:15,050 I can say print student. 749 00:38:15,050 --> 00:38:19,700 Now it doesn't matter if I have 3 students or 4 or 400, 750 00:38:19,700 --> 00:38:23,930 these two lines of code, this loop will print all of those students for me 751 00:38:23,930 --> 00:38:24,810 one at a time. 752 00:38:24,810 --> 00:38:28,490 So if I now run Python of hogwarts.py, there's the same list, 753 00:38:28,490 --> 00:38:32,420 but I don't need to know in advance how long that actual list is. 754 00:38:32,420 --> 00:38:35,130 Now notice, I made a conscious decision here. 755 00:38:35,130 --> 00:38:39,680 I didn't call this variable underscore, because this time I'm 756 00:38:39,680 --> 00:38:40,970 using the variable. 757 00:38:40,970 --> 00:38:44,210 And while I could do this, now, no, no, no, no, 758 00:38:44,210 --> 00:38:46,130 your code is getting way too cryptic. 759 00:38:46,130 --> 00:38:48,860 If you're naming the variable underscore and you're 760 00:38:48,860 --> 00:38:51,530 using the variable underscore, now you're helping no one. 761 00:38:51,530 --> 00:38:54,890 Now you're confusing the reader, yourself down the line, 762 00:38:54,890 --> 00:38:57,370 you should call your variables what they are. 763 00:38:57,370 --> 00:39:00,470 So a very appropriate name, though I'm sure you could come up with others, 764 00:39:00,470 --> 00:39:04,430 would be student, and here, you could say you would stay student as well. 765 00:39:04,430 --> 00:39:06,710 If you'd prefer to be more succinct, it's 766 00:39:06,710 --> 00:39:09,380 not unreasonable to do something succinct in a loop like this. 767 00:39:09,380 --> 00:39:13,430 For s in students, using maybe the same letter that the list 768 00:39:13,430 --> 00:39:15,740 itself begins with, but again, why bother? 769 00:39:15,740 --> 00:39:17,510 Python is meant to be more readable. 770 00:39:17,510 --> 00:39:22,530 If you have a list of students, iterate over them one student at a time. 771 00:39:22,530 --> 00:39:25,490 Let me pause here to see if there's now questions about lists 772 00:39:25,490 --> 00:39:28,220 as I've now defined them, a list of strings in this case, 773 00:39:28,220 --> 00:39:33,860 or using a for loop now to iterate over and print each of those names. 774 00:39:33,860 --> 00:39:34,550 AUDIENCE: Yeah. 775 00:39:34,550 --> 00:39:38,150 So is it not necessary to initiate student in this case? 776 00:39:38,150 --> 00:39:40,575 Or we can just declare a variable in the loop? 777 00:39:40,575 --> 00:39:41,700 DAVID MALAN: Good question. 778 00:39:41,700 --> 00:39:43,450 You do not need to manually initialize it. 779 00:39:43,450 --> 00:39:47,810 Python takes care of initializing the student variable to Hermione 780 00:39:47,810 --> 00:39:49,960 first, then Harry second, then Ron third. 781 00:39:49,960 --> 00:39:53,210 Unlike other languages, you don't need to initialize it to something yourself, 782 00:39:53,210 --> 00:39:55,250 it just exists and it will work. 783 00:39:55,250 --> 00:39:58,662 Other questions on loops and lists in this way? 784 00:39:58,662 --> 00:40:00,620 AUDIENCE: Since you describe break, so is there 785 00:40:00,620 --> 00:40:04,232 any concept of continuing so that we can skip a particular case in loops? 786 00:40:04,232 --> 00:40:04,940 DAVID MALAN: Yes. 787 00:40:04,940 --> 00:40:06,933 You can continue using another syntax as well. 788 00:40:06,933 --> 00:40:07,850 We haven't shown that. 789 00:40:07,850 --> 00:40:10,668 For now we focused only on break. 790 00:40:10,668 --> 00:40:11,210 AUDIENCE: OK. 791 00:40:11,210 --> 00:40:15,770 So can this for loop work with either hash tables or different kind 792 00:40:15,770 --> 00:40:17,607 of tables or arrays? 793 00:40:17,607 --> 00:40:18,440 DAVID MALAN: Indeed. 794 00:40:18,440 --> 00:40:20,190 So we're getting ahead of ourselves there, 795 00:40:20,190 --> 00:40:22,610 but there are yet other types of data in Python, 796 00:40:22,610 --> 00:40:26,550 and indeed, you can use a for loop to iterate over those as well. 797 00:40:26,550 --> 00:40:28,940 Anything that is iterable, so to speak, is 798 00:40:28,940 --> 00:40:32,030 a piece of data that can be used with a loop like this. 799 00:40:32,030 --> 00:40:34,290 But more on those-- more on those soon. 800 00:40:34,290 --> 00:40:37,967 In fact, let me transition here to show just another way of solving 801 00:40:37,967 --> 00:40:40,550 this same problem, because up until now when we've used loops, 802 00:40:40,550 --> 00:40:43,040 we really have relied on numbers, and that's fine 803 00:40:43,040 --> 00:40:45,620 if you prefer to stay in that space. 804 00:40:45,620 --> 00:40:49,610 Suppose I did want to iterate using numbers like i and 0, 805 00:40:49,610 --> 00:40:50,910 1, 2, and so forth. 806 00:40:50,910 --> 00:40:53,700 Let me propose that we could change this code as follows. 807 00:40:53,700 --> 00:40:56,930 If you would prefer to think about, or if the program you're 808 00:40:56,930 --> 00:40:59,810 trying to implement requires that you use numbers like this, 809 00:40:59,810 --> 00:41:00,830 you might do this. 810 00:41:00,830 --> 00:41:04,820 For i in-- well, I don't want to just say students, 811 00:41:04,820 --> 00:41:07,580 because then i is not going to be a number. 812 00:41:07,580 --> 00:41:13,010 i is going to be literally Hermione, then Harry, then Ron. 813 00:41:13,010 --> 00:41:17,030 I need to iterate from 0 to 1 to 2. 814 00:41:17,030 --> 00:41:21,320 If I a list with three elements has these locations, 0, 1, 2, 815 00:41:21,320 --> 00:41:25,400 I need to create a loop somehow that starts at 0 and ends at 2. 816 00:41:25,400 --> 00:41:28,340 Previously when I wanted to do that, I needed range, 817 00:41:28,340 --> 00:41:30,290 but this 2 is not going to work. 818 00:41:30,290 --> 00:41:32,750 I can't just say in the range of students, 819 00:41:32,750 --> 00:41:36,030 because students is not a number, it's not an integer, 820 00:41:36,030 --> 00:41:37,640 so you can't pass it to range. 821 00:41:37,640 --> 00:41:39,260 Range expects an integer. 822 00:41:39,260 --> 00:41:41,840 But there is a solution here. 823 00:41:41,840 --> 00:41:47,390 It turns out that there is a function in Python called length or len, L-E-N, 824 00:41:47,390 --> 00:41:51,890 that will tell you the length of a list and other things down the line, too. 825 00:41:51,890 --> 00:41:55,850 And now I think I can assemble these building blocks and a way that can 826 00:41:55,850 --> 00:41:57,740 allow me to use numbers in this way. 827 00:41:57,740 --> 00:42:02,870 So range doesn't take a list of strings, it takes a number, 828 00:42:02,870 --> 00:42:04,790 and ideally, that number is going to be 3, 829 00:42:04,790 --> 00:42:07,580 so I get a range of values, 0, 1, and 2. 830 00:42:07,580 --> 00:42:10,640 So I think I can nest my functions like this. 831 00:42:10,640 --> 00:42:15,410 If I first get the length of the students list, that's going to be 3, 832 00:42:15,410 --> 00:42:18,620 then I pass that return value as the argument 833 00:42:18,620 --> 00:42:23,840 to range, that's going to give me back a range of values, 0, then 1, then 2. 834 00:42:23,840 --> 00:42:26,570 And what that's going to allow me to do then in code if I want 835 00:42:26,570 --> 00:42:28,310 is not just this. 836 00:42:28,310 --> 00:42:33,650 I could do print now students bracket i, and this is now 837 00:42:33,650 --> 00:42:38,270 where the syntax we're seeing is getting very expressive-- new and perhaps 838 00:42:38,270 --> 00:42:39,200 unfamiliar. 839 00:42:39,200 --> 00:42:44,090 But if I can do open bracket, 0, close bracket, or open bracket, 1, 840 00:42:44,090 --> 00:42:47,990 close bracket, or open bracket, 2, close bracket, turns out, 841 00:42:47,990 --> 00:42:49,940 I can actually put a variable in there and I 842 00:42:49,940 --> 00:42:52,490 can express any number inside of those brackets 843 00:42:52,490 --> 00:42:54,800 so as to print these all out dynamically in a loop. 844 00:42:54,800 --> 00:42:57,680 Let me do this, Python of hogwarts.py, Enter, 845 00:42:57,680 --> 00:43:00,140 there's Hermione, Harry, and Ron. 846 00:43:00,140 --> 00:43:02,570 And now if I'm just curious, I just want to poke 847 00:43:02,570 --> 00:43:05,060 around or maybe I want to do a ranking, like who 848 00:43:05,060 --> 00:43:08,240 are the top three students in the school or in Gryffindor? 849 00:43:08,240 --> 00:43:11,000 Well, I can print multiple things at a time, we've seen. 850 00:43:11,000 --> 00:43:14,540 Let me print out not just the students at location 851 00:43:14,540 --> 00:43:19,340 i, but rather, let's print i first and then the student at location i. 852 00:43:19,340 --> 00:43:22,850 So two things to print, and we know that print can take two arguments, 853 00:43:22,850 --> 00:43:25,280 we've seen that before, they'll be separated by a space. 854 00:43:25,280 --> 00:43:26,900 Let me go ahead and rerun this. 855 00:43:26,900 --> 00:43:31,533 Now I see that, OK, Hermione is the top student, but she's in zeroth place. 856 00:43:31,533 --> 00:43:32,450 That's a little weird. 857 00:43:32,450 --> 00:43:35,930 Like we don't need to show the human using my program 858 00:43:35,930 --> 00:43:37,430 that we started counting at 0. 859 00:43:37,430 --> 00:43:38,570 I can clean this up. 860 00:43:38,570 --> 00:43:41,600 I can just add 1 to the i up here, and now we 861 00:43:41,600 --> 00:43:43,640 see a top three list of students. 862 00:43:43,640 --> 00:43:47,540 Hermione is number 1, Harry's number 2, and of course, Ron is number 3. 863 00:43:47,540 --> 00:43:50,960 So we can get access to all of those same values as well. 864 00:43:50,960 --> 00:43:55,320 Are there any questions now on these lists? 865 00:43:55,320 --> 00:43:58,320 Any questions now on these lists? 866 00:43:58,320 --> 00:44:01,050 This length, these ranges, or otherwise? 867 00:44:01,050 --> 00:44:08,350 AUDIENCE: My question is, for i in range, can you explain this once more? 868 00:44:08,350 --> 00:44:10,210 DAVID MALAN: Sure. 869 00:44:10,210 --> 00:44:12,640 So let me rewind in time. 870 00:44:12,640 --> 00:44:13,960 We started off doing this. 871 00:44:13,960 --> 00:44:20,770 For i in 0, 1, 2, and then we print it out meow three times in that way. 872 00:44:20,770 --> 00:44:23,830 The way that for loop works is that it creates 873 00:44:23,830 --> 00:44:27,730 for you a variable that I've called i, but I could call it anything I want. 874 00:44:27,730 --> 00:44:31,390 It then assigns i initially to the first thing in the list. 875 00:44:31,390 --> 00:44:34,690 It then automatically assigns i to the next thing in the list. 876 00:44:34,690 --> 00:44:37,210 And then it assigns i to the third thing in the list. 877 00:44:37,210 --> 00:44:41,520 And each time it does all of the indented code underneath. 878 00:44:41,520 --> 00:44:43,740 We realize, though, that this is not going 879 00:44:43,740 --> 00:44:46,380 to scale well if I want to do something like a million times. 880 00:44:46,380 --> 00:44:48,480 So we introduced range instead. 881 00:44:48,480 --> 00:44:51,240 That has the effect of doing the same thing. 882 00:44:51,240 --> 00:44:55,080 It returns to me a range of values-- a list of three things, really, 883 00:44:55,080 --> 00:44:57,330 so the behavior is exactly the same. 884 00:44:57,330 --> 00:45:01,890 If we now fast forward to this Hogwarts example now, though, what I'm doing 885 00:45:01,890 --> 00:45:04,500 is just combining these smaller ideas. 886 00:45:04,500 --> 00:45:06,330 I'm still creating a for loop. 887 00:45:06,330 --> 00:45:08,520 I'm still creating a variable called i. 888 00:45:08,520 --> 00:45:11,760 I want to do it over a range of values, but how many values? 889 00:45:11,760 --> 00:45:15,390 Well, if I use the length function and pass to the length function 890 00:45:15,390 --> 00:45:18,300 the list of values, length's purpose in life 891 00:45:18,300 --> 00:45:21,120 is to tell me how long is this list, and it's 3. 892 00:45:21,120 --> 00:45:25,740 So that's almost as though before, I had just done something like this, 893 00:45:25,740 --> 00:45:29,220 but I don't want to hardcode 3, I want to dynamically figure out 894 00:45:29,220 --> 00:45:30,870 how many students are at Hogwarts. 895 00:45:30,870 --> 00:45:32,910 So I'm just composing, composing, composing, 896 00:45:32,910 --> 00:45:36,210 or nesting all of these various ideas. 897 00:45:36,210 --> 00:45:38,880 All right, if I may, let me transition now to-- 898 00:45:38,880 --> 00:45:42,540 in Hogwarts still to introduce one final type of data before 899 00:45:42,540 --> 00:45:45,690 we combine everything with a few final programs. 900 00:45:45,690 --> 00:45:49,410 It turns out in Python, there's not just strings, not just 901 00:45:49,410 --> 00:45:51,600 ints, not just floating point values, not 902 00:45:51,600 --> 00:45:53,790 just bools, not just lists there are also 903 00:45:53,790 --> 00:45:58,560 what are called dictionaries or dics, are a data structure that allows you 904 00:45:58,560 --> 00:46:02,250 to associate one value with another. 905 00:46:02,250 --> 00:46:04,380 Literally a dictionary like in the human world. 906 00:46:04,380 --> 00:46:07,680 If you were to open a dictionary, be it in English or any other human language, 907 00:46:07,680 --> 00:46:09,190 what's inside of a dictionary? 908 00:46:09,190 --> 00:46:12,480 Well, it's a bunch of words and definitions. 909 00:46:12,480 --> 00:46:14,760 A computer scientist, though, and a programmer 910 00:46:14,760 --> 00:46:19,470 would describe those more generically as keys and values, something 911 00:46:19,470 --> 00:46:21,360 associated with something else. 912 00:46:21,360 --> 00:46:22,950 That's all a dictionary is. 913 00:46:22,950 --> 00:46:25,930 It allows you to associate something with something else. 914 00:46:25,930 --> 00:46:29,160 And notice, this is already more powerful, more interesting than a list. 915 00:46:29,160 --> 00:46:32,670 A list is just a set of multiple values. 916 00:46:32,670 --> 00:46:36,240 But a dictionary is two-dimensional, if you will. 917 00:46:36,240 --> 00:46:39,390 Just like a human dictionary, a book, it associates something 918 00:46:39,390 --> 00:46:42,210 with something else like words with their definitions. 919 00:46:42,210 --> 00:46:44,500 Now what does this actually mean in practice? 920 00:46:44,500 --> 00:46:48,390 Well suppose that we wanted to keep track 921 00:46:48,390 --> 00:46:51,810 of who is in what house at Hogwarts. 922 00:46:51,810 --> 00:46:54,240 Well, I could do it using lists alone. 923 00:46:54,240 --> 00:46:55,950 Let me go back to VS Code here and let me 924 00:46:55,950 --> 00:46:59,470 just temporarily-- but in a way that I'm not going to like ultimately-- 925 00:46:59,470 --> 00:47:01,620 let me create another variable called houses, 926 00:47:01,620 --> 00:47:06,750 set it equal to Gryffindor, corresponding to Hermione's house, 927 00:47:06,750 --> 00:47:09,960 Gryffindor, corresponding to Harry's house, and Gryffindor, 928 00:47:09,960 --> 00:47:11,250 corresponding to Ron's house. 929 00:47:11,250 --> 00:47:12,730 And let's add Draco in there. 930 00:47:12,730 --> 00:47:14,640 So we now have four instead of three students 931 00:47:14,640 --> 00:47:18,810 just so we have a little variety, and he was in Slytherin. 932 00:47:18,810 --> 00:47:21,300 So now we have two lists. 933 00:47:21,300 --> 00:47:24,750 And we could just agree amongst ourselves 934 00:47:24,750 --> 00:47:28,680 that whoever is first in the students variable lives 935 00:47:28,680 --> 00:47:31,410 in the first value in houses. 936 00:47:31,410 --> 00:47:34,770 Whoever is second in students lives in the second house. 937 00:47:34,770 --> 00:47:37,680 Who's ever third in students lives in the third house. 938 00:47:37,680 --> 00:47:38,730 We could do that. 939 00:47:38,730 --> 00:47:41,430 But honestly, that is going to break down quickly 940 00:47:41,430 --> 00:47:44,102 when we have a lot of students, when we have a lot of houses, 941 00:47:44,102 --> 00:47:46,560 and what if we want to keep track of more things than that? 942 00:47:46,560 --> 00:47:48,810 What if we want to keep track of every student's house 943 00:47:48,810 --> 00:47:52,890 and the patronus, this image that they conjure up magically? 944 00:47:52,890 --> 00:47:55,290 Well, then we need a third list like-- this is just 945 00:47:55,290 --> 00:47:58,440 going to get messy quickly if we're just on the honor system 946 00:47:58,440 --> 00:48:02,640 using multiple lists where everything lines up logically. 947 00:48:02,640 --> 00:48:05,940 It doesn't end up well when your code gets more complicated. 948 00:48:05,940 --> 00:48:07,740 But I do want to implement this idea. 949 00:48:07,740 --> 00:48:09,990 I want to associate something with something. 950 00:48:09,990 --> 00:48:12,960 A student with a house, a student with a house, a student with a house 951 00:48:12,960 --> 00:48:15,970 and so forth, so how can I go about doing this? 952 00:48:15,970 --> 00:48:18,570 Well, let me go back to my code here and let 953 00:48:18,570 --> 00:48:22,410 me propose that we do this using a Python dictionary. 954 00:48:22,410 --> 00:48:25,560 And this is the last of the new syntax, really, that we'll see . 955 00:48:25,560 --> 00:48:26,880 Here's the new syntax. 956 00:48:26,880 --> 00:48:29,280 Instead of using square brackets, we're going 957 00:48:29,280 --> 00:48:32,500 to use curly braces for dictionaries as well. 958 00:48:32,500 --> 00:48:37,050 We've seen curly braces in the context of f strings completely unrelated. 959 00:48:37,050 --> 00:48:40,360 Sometimes you run out of keys on the keyboard and the authors of a language 960 00:48:40,360 --> 00:48:43,302 need to start reusing symbols in different ways, that's 961 00:48:43,302 --> 00:48:44,260 what's about to happen. 962 00:48:44,260 --> 00:48:46,150 We're using curly braces in a different way. 963 00:48:46,150 --> 00:48:48,690 Now so let me create a variable called students. 964 00:48:48,690 --> 00:48:51,960 And let me go ahead and set it equal to open 965 00:48:51,960 --> 00:48:54,030 curly brace and closed curly brace. 966 00:48:54,030 --> 00:48:56,670 This is an empty dictionary at the moment. 967 00:48:56,670 --> 00:48:58,590 And here's how a dictionary works. 968 00:48:58,590 --> 00:49:01,150 It allows you to associate something with something else, 969 00:49:01,150 --> 00:49:02,400 and you do that like this. 970 00:49:02,400 --> 00:49:07,777 Hermione, quote-unquote, colon, and then the value thereof. 971 00:49:07,777 --> 00:49:09,610 What do you want to associate with Hermione? 972 00:49:09,610 --> 00:49:11,280 Well, Gryffindor. 973 00:49:11,280 --> 00:49:13,680 What do I want to associate Harry with? 974 00:49:13,680 --> 00:49:16,560 Well, I want to associate him with Gryffindor. 975 00:49:16,560 --> 00:49:18,630 What do I want to associate Ron with? 976 00:49:18,630 --> 00:49:21,240 Well, I want to associate him with Gryffindor. 977 00:49:21,240 --> 00:49:24,600 Well, this is actually not going to-- this is going to get very ugly quickly. 978 00:49:24,600 --> 00:49:27,502 Once we add in Draco and Slytherin, my code is going to get too long, 979 00:49:27,502 --> 00:49:28,710 it's going to start wrapping. 980 00:49:28,710 --> 00:49:30,390 So this is purely aesthetic. 981 00:49:30,390 --> 00:49:33,450 It is perfectly acceptable in Python and other languages 982 00:49:33,450 --> 00:49:36,570 to format your code a little more readily and just add new lines 983 00:49:36,570 --> 00:49:38,040 if it makes it more readable. 984 00:49:38,040 --> 00:49:40,480 And one way of doing this might be as follows. 985 00:49:40,480 --> 00:49:44,920 I still have my curly brace up here, I still have my curly brace down here, 986 00:49:44,920 --> 00:49:47,400 but notice, it's a little more readable now 987 00:49:47,400 --> 00:49:51,743 in that I have my keys on the left, my somethings, and my values 988 00:49:51,743 --> 00:49:53,160 on the right, my other somethings. 989 00:49:53,160 --> 00:49:55,800 It's just a little easier to skim top to bottom. 990 00:49:55,800 --> 00:49:57,480 You could format it differently as well. 991 00:49:57,480 --> 00:50:00,690 But I'm going to go ahead and add in now Draco 992 00:50:00,690 --> 00:50:03,210 who lives, of course, in Slytherin. 993 00:50:03,210 --> 00:50:07,320 So now I have each of these keys on the left 994 00:50:07,320 --> 00:50:09,910 and values on the right, which is really, again, 995 00:50:09,910 --> 00:50:13,200 just a code implementation of this idea, a little chart 996 00:50:13,200 --> 00:50:15,300 that you might write up with paper pencil 997 00:50:15,300 --> 00:50:17,620 when associating something with something else. 998 00:50:17,620 --> 00:50:20,680 So how do I now use this code in an interesting way? 999 00:50:20,680 --> 00:50:22,230 The syntax is almost the same. 1000 00:50:22,230 --> 00:50:26,160 If I want to print out the very first student, Hermione's house, 1001 00:50:26,160 --> 00:50:27,150 I could do this. 1002 00:50:27,150 --> 00:50:31,960 Print out the name of the variable, but I need to go inside of the variable. 1003 00:50:31,960 --> 00:50:33,810 I need to index into it. 1004 00:50:33,810 --> 00:50:38,280 And what's neat about dictionaries is that whereas lists 1005 00:50:38,280 --> 00:50:41,010 have locations that are numeric-- 1006 00:50:41,010 --> 00:50:45,270 0, 1, 2; Hermione, Harry, Ron respectively, 1007 00:50:45,270 --> 00:50:50,520 dictionaries allow you to use actual words as your indices, so to speak, 1008 00:50:50,520 --> 00:50:52,750 your indexes to get inside of them. 1009 00:50:52,750 --> 00:50:55,740 So if you want to print out Hermione's house, 1010 00:50:55,740 --> 00:50:59,160 the key you care about is, quote-unquote, Hermione, 1011 00:50:59,160 --> 00:51:04,050 and what this syntax here will do-- notice, it's not a number 0 or 1 or 2. 1012 00:51:04,050 --> 00:51:05,970 It's literally Hermione's name. 1013 00:51:05,970 --> 00:51:11,070 This is like going to the chart earlier and saying, all right, give me Hermione 1014 00:51:11,070 --> 00:51:13,628 is my key, Gryffindor is the value. 1015 00:51:13,628 --> 00:51:15,420 That's what we're doing here syntactically. 1016 00:51:15,420 --> 00:51:18,300 We're looking up Hermione and getting the value thereof. 1017 00:51:18,300 --> 00:51:21,120 So if I go back to my code, that should print out Gryffindor. 1018 00:51:21,120 --> 00:51:24,330 And if I do this a few times, students, bracket, quote-unquote, 1019 00:51:24,330 --> 00:51:26,280 Harry should give me Harry's house. 1020 00:51:26,280 --> 00:51:30,630 Print students, open bracket, Ron, that should give me Ron's house. 1021 00:51:30,630 --> 00:51:33,660 And then lastly, if I do this with students, bracket, Draco, 1022 00:51:33,660 --> 00:51:35,727 that should give me Draco's house. 1023 00:51:35,727 --> 00:51:38,310 Now it's a little manual still, and I bet we can improve this, 1024 00:51:38,310 --> 00:51:40,620 but let me run Python on hogwarts.py and we 1025 00:51:40,620 --> 00:51:44,790 should see Gryffindor, Gryffindor, Gryffindor, Slytherin, which 1026 00:51:44,790 --> 00:51:46,500 is exactly what we'd expect. 1027 00:51:46,500 --> 00:51:48,810 Now all we've done, again, is we've just now moved 1028 00:51:48,810 --> 00:51:52,710 from having just a simple list of names to, again, two dimensions, 1029 00:51:52,710 --> 00:51:56,070 associating like we would on paper-pencil something with something 1030 00:51:56,070 --> 00:51:58,920 else, keys with values respectively. 1031 00:51:58,920 --> 00:52:02,580 Allow me, if you will, even though I realize this is getting a little fancy, 1032 00:52:02,580 --> 00:52:07,200 allow me to escalate things slightly here and transition from looking 1033 00:52:07,200 --> 00:52:13,020 at just, for instance, that pattern there, just a hard coding those values 1034 00:52:13,020 --> 00:52:15,660 there to actually printing these out more dynamically. 1035 00:52:15,660 --> 00:52:19,510 Let me go ahead and use our loop, and this question came up earlier as well, 1036 00:52:19,510 --> 00:52:25,450 let me go ahead and say for each student in students, 1037 00:52:25,450 --> 00:52:31,240 go ahead and print out, for instance, the students variable at-- 1038 00:52:31,240 --> 00:52:32,920 well, let's just say student first. 1039 00:52:32,920 --> 00:52:33,950 Let's keep it simple. 1040 00:52:33,950 --> 00:52:35,950 So this is not going to be that interesting yet, 1041 00:52:35,950 --> 00:52:41,470 but when I run Python of hogwarts.py and hit Enter, notice, what should I see? 1042 00:52:41,470 --> 00:52:44,200 Let me take a question here to see what am I 1043 00:52:44,200 --> 00:52:48,910 going to see when I hit Enter now when I'm doing for student in students? 1044 00:52:48,910 --> 00:52:51,305 AUDIENCE: Yeah, I think we will only see keys. 1045 00:52:51,305 --> 00:52:52,180 DAVID MALAN: Perfect. 1046 00:52:52,180 --> 00:52:53,020 So good intuition. 1047 00:52:53,020 --> 00:52:53,980 It could have gone both ways. 1048 00:52:53,980 --> 00:52:55,540 Could have been values, the houses. 1049 00:52:55,540 --> 00:53:01,300 But when you use a for loop in Python to iterate over a dictionary, by design, 1050 00:53:01,300 --> 00:53:03,550 it iterates over all of the keys. 1051 00:53:03,550 --> 00:53:07,960 So we should see, I think, Hermione, Harry, Ron, and Draco. 1052 00:53:07,960 --> 00:53:11,260 Let me hit Enter now, Enter, and indeed, you're exactly right, 1053 00:53:11,260 --> 00:53:12,580 we see just the keys. 1054 00:53:12,580 --> 00:53:15,580 But that's not really that useful if what I really care about 1055 00:53:15,580 --> 00:53:18,430 is who lives where, can I print out both? 1056 00:53:18,430 --> 00:53:19,930 Well, I think I can. 1057 00:53:19,930 --> 00:53:21,350 Let me go ahead and do this. 1058 00:53:21,350 --> 00:53:24,850 Let me print out not just the student's name, the key, 1059 00:53:24,850 --> 00:53:30,537 but let me use the key, their name, to index into the dictionary. 1060 00:53:30,537 --> 00:53:33,370 If I know the word in the dictionary, let me look up its definition. 1061 00:53:33,370 --> 00:53:35,980 If I know the student's name, let me look up their house, 1062 00:53:35,980 --> 00:53:40,720 and the syntax for this, just like a list, is students, bracket. 1063 00:53:40,720 --> 00:53:44,480 And just like in the past we used i when i was a number, 1064 00:53:44,480 --> 00:53:48,080 we can also with a dictionary use a string. 1065 00:53:48,080 --> 00:53:55,180 So if the student's name is the key, then this syntax, students, 1066 00:53:55,180 --> 00:54:00,340 open bracket, student, close bracket will go to Hermione's location 1067 00:54:00,340 --> 00:54:01,330 and get back her house. 1068 00:54:01,330 --> 00:54:04,970 Will go to Harry's location and get back his house and so forth. 1069 00:54:04,970 --> 00:54:08,943 So if I do Python of hogwarts.py, Enter, now I 1070 00:54:08,943 --> 00:54:11,485 see Hermione, Gryffindor; Harry, Gryffindor; Ron, Gryffindor; 1071 00:54:11,485 --> 00:54:12,730 and Draco Slytherin. 1072 00:54:12,730 --> 00:54:14,940 Now it looks like I've given them all new last names, 1073 00:54:14,940 --> 00:54:15,940 but I can clean that up. 1074 00:54:15,940 --> 00:54:17,170 This is just a print thing. 1075 00:54:17,170 --> 00:54:20,110 Let's go ahead and change our separator from the default space 1076 00:54:20,110 --> 00:54:21,790 to maybe a space, comma. 1077 00:54:21,790 --> 00:54:26,110 And just using print features now, let me run the same program again, Enter, 1078 00:54:26,110 --> 00:54:29,050 now I've just got some nice pretty commas in there to make clear 1079 00:54:29,050 --> 00:54:31,810 that Hermione's last name is not, in fact, Gryffindor, 1080 00:54:31,810 --> 00:54:33,730 but that's just a print detail. 1081 00:54:33,730 --> 00:54:37,120 Any questions, then, on these dictionaries and what I've just done? 1082 00:54:37,120 --> 00:54:39,650 1083 00:54:39,650 --> 00:54:45,410 Questions on these dictionaries and this looping over then here? 1084 00:54:45,410 --> 00:54:52,190 AUDIENCE: I just can't get my head around the for student in students. 1085 00:54:52,190 --> 00:54:54,860 If I'm-- just correct me if I'm right. 1086 00:54:54,860 --> 00:55:01,850 Does that mean it imports the list of students and uses the indexes-- 1087 00:55:01,850 --> 00:55:09,140 or in other words, Hermione, Harry, and Ron as the indexes in the actual-- 1088 00:55:09,140 --> 00:55:10,455 the list of students? 1089 00:55:10,455 --> 00:55:11,330 DAVID MALAN: Correct. 1090 00:55:11,330 --> 00:55:13,100 So this is just a feature of Python. 1091 00:55:13,100 --> 00:55:17,150 When you use a for loop with a dictionary, what happens is this. 1092 00:55:17,150 --> 00:55:20,513 If this is the dictionary here with the keys on top and the values on bottom, 1093 00:55:20,513 --> 00:55:22,430 you get to choose what the variable is called. 1094 00:55:22,430 --> 00:55:24,818 I called my variable student just because it makes sense, 1095 00:55:24,818 --> 00:55:26,360 because I want one student at a time. 1096 00:55:26,360 --> 00:55:29,510 And what for loop does, just like it did with numbers before, 1097 00:55:29,510 --> 00:55:33,060 the 0, the 1, and the 2, it allows me to, for instance, 1098 00:55:33,060 --> 00:55:35,810 set student equal initially to Hermelin's name. 1099 00:55:35,810 --> 00:55:38,990 And then the next iteration of the loop, the next cycle, 1100 00:55:38,990 --> 00:55:42,800 sets student equal to Harry's name, then Ron, then Draco. 1101 00:55:42,800 --> 00:55:44,300 It just happens automatically. 1102 00:55:44,300 --> 00:55:47,480 Like that is what the Python interpreter does for you when 1103 00:55:47,480 --> 00:55:49,140 it sees a for loop like that. 1104 00:55:49,140 --> 00:55:53,090 So it's very similar in spirit to iterating with a for loop over a list, 1105 00:55:53,090 --> 00:55:55,670 but rather than iterate over the numeric location, 1106 00:55:55,670 --> 00:56:01,700 0, 1, 2, it iterates over the bold-faced keys in this representation here 1107 00:56:01,700 --> 00:56:02,930 graphically. 1108 00:56:02,930 --> 00:56:05,960 And allow me to give us one other example on Hogwarts 1109 00:56:05,960 --> 00:56:09,320 before we look at one other familiar domain. 1110 00:56:09,320 --> 00:56:11,670 At the risk of things escalating a little bit, 1111 00:56:11,670 --> 00:56:15,320 let me propose that we continue the story with one final Hogwarts 1112 00:56:15,320 --> 00:56:17,100 example like this. 1113 00:56:17,100 --> 00:56:21,280 What if we have more information about each of our students? 1114 00:56:21,280 --> 00:56:23,030 And this is inevitable. 1115 00:56:23,030 --> 00:56:26,760 If you're implementing a program that's a database with people or customers, 1116 00:56:26,760 --> 00:56:29,060 or employees or anything else, you can imagine 1117 00:56:29,060 --> 00:56:33,230 having a lot of data about anything you're representing in your program 1118 00:56:33,230 --> 00:56:33,740 here. 1119 00:56:33,740 --> 00:56:37,470 For the sake of discussion, suppose that every student at Hogwarts, of course, 1120 00:56:37,470 --> 00:56:41,480 has a name, they have already a house, but they also have a patronus. 1121 00:56:41,480 --> 00:56:44,360 For those unfamiliar, this is the animal or entity 1122 00:56:44,360 --> 00:56:48,260 that comes out of the end of their wand when they make a certain magical spell. 1123 00:56:48,260 --> 00:56:51,410 The point here being is that we want to associate not 1124 00:56:51,410 --> 00:56:55,670 just one thing with the student, but multiple things 1125 00:56:55,670 --> 00:57:00,110 as well-- their name, their house, and their patronus in this case. 1126 00:57:00,110 --> 00:57:02,400 Well, what might code like this look like? 1127 00:57:02,400 --> 00:57:07,100 Well, let me go back to hogwarts.py and let me start fresh for just a moment. 1128 00:57:07,100 --> 00:57:10,650 And let me propose that I enhance this with a bit more data. 1129 00:57:10,650 --> 00:57:12,800 And this data is going to look as follows. 1130 00:57:12,800 --> 00:57:18,360 My students variable now, I'm going to propose we think of it as a list. 1131 00:57:18,360 --> 00:57:21,320 What if we have a list of dictionaries as follows? 1132 00:57:21,320 --> 00:57:24,960 Indeed I want to literally implement this picture here. 1133 00:57:24,960 --> 00:57:29,210 So notice that my previous picture just represented a single dictionary. 1134 00:57:29,210 --> 00:57:33,500 But suppose I wanted to compose a list of dictionaries. 1135 00:57:33,500 --> 00:57:36,650 That is, for students-- so a list of four students. 1136 00:57:36,650 --> 00:57:41,240 And suppose that each of those students is itself a dictionary, 1137 00:57:41,240 --> 00:57:46,130 a collection of key value pairs, keys and values, 1138 00:57:46,130 --> 00:57:48,180 something and something else. 1139 00:57:48,180 --> 00:57:50,990 Well, here's one other way we can do this in code. 1140 00:57:50,990 --> 00:57:55,130 Let me go back to VS Code here and let me define a variable called 1141 00:57:55,130 --> 00:57:58,100 students that is equal to a list. 1142 00:57:58,100 --> 00:58:01,343 And I'm going to preemptively move my cursor onto separate lines, 1143 00:58:01,343 --> 00:58:03,260 because I know this is going to be long, and I 1144 00:58:03,260 --> 00:58:07,320 want to fit all of the elements of this list inside of it. 1145 00:58:07,320 --> 00:58:10,555 I'm now going to create a dictionary, one dictionary per student. 1146 00:58:10,555 --> 00:58:11,930 And how do I create a dictionary? 1147 00:58:11,930 --> 00:58:13,670 I just use those curly braces. 1148 00:58:13,670 --> 00:58:16,220 But it's up to me to define what those keys are. 1149 00:58:16,220 --> 00:58:18,500 And let me propose that one key this time 1150 00:58:18,500 --> 00:58:20,750 won't be the student's name explicitly, it 1151 00:58:20,750 --> 00:58:24,980 will literally be the word name, and there, going to have the name Hermione. 1152 00:58:24,980 --> 00:58:28,700 The same student is going to have another key called house 1153 00:58:28,700 --> 00:58:31,010 and the value is going to be Gryffindor. 1154 00:58:31,010 --> 00:58:34,700 And the same student is going to have a third key called patronus, 1155 00:58:34,700 --> 00:58:36,620 and the value of that is going to be-- 1156 00:58:36,620 --> 00:58:39,710 I had to look it up-- an otter, according to the book. 1157 00:58:39,710 --> 00:58:43,012 Now I'm going to create a second dictionary inside of this list. 1158 00:58:43,012 --> 00:58:44,720 And again, a dictionary is like literally 1159 00:58:44,720 --> 00:58:46,710 like the human dictionary of words. 1160 00:58:46,710 --> 00:58:50,750 It's a book that contains keys and values, words and definitions. 1161 00:58:50,750 --> 00:58:53,630 What are the three words I'm storing in each of my dictionaries? 1162 00:58:53,630 --> 00:58:55,640 Name, house, and patronus. 1163 00:58:55,640 --> 00:58:58,940 What are the definitions of those words for Hermione? 1164 00:58:58,940 --> 00:59:01,850 Hermione, Gryffindor, and otter respectively. 1165 00:59:01,850 --> 00:59:05,840 For Harry, the definitions are going to be different in this new dictionary. 1166 00:59:05,840 --> 00:59:08,270 Let me give myself another pair of curly braces 1167 00:59:08,270 --> 00:59:12,230 and say this, name, quote-unquote, colon, Harry. 1168 00:59:12,230 --> 00:59:15,500 House here is, again, going to be Gryffindor. 1169 00:59:15,500 --> 00:59:21,620 And this one I knew, his patronus, is going to be, in this case, a stag. 1170 00:59:21,620 --> 00:59:23,330 Next, a third dictionary. 1171 00:59:23,330 --> 00:59:25,130 The name here will be Ron. 1172 00:59:25,130 --> 00:59:27,560 And I'm going to go ahead and do that just like this. 1173 00:59:27,560 --> 00:59:31,070 Next, I have the house, and he, too, was Gryffindor. 1174 00:59:31,070 --> 00:59:38,120 Lastly, had to look this one up, Ron's patronus was a Jack Russell terrier. 1175 00:59:38,120 --> 00:59:42,100 Lastly is Draco. 1176 00:59:42,100 --> 00:59:45,070 In a fourth dictionary now-- so another pair of curly braces, 1177 00:59:45,070 --> 00:59:47,380 the name of the student is, of course, Draco. 1178 00:59:47,380 --> 00:59:50,650 The house of this student is Slytherin. 1179 00:59:50,650 --> 00:59:55,630 And Draco, interestingly enough, at least according to the internet, 1180 00:59:55,630 --> 00:59:57,010 has no patronus. 1181 00:59:57,010 --> 00:59:59,230 Was never revealed in the books or the movies. 1182 00:59:59,230 --> 01:00:02,290 So it turns out, this is actually a wonderful teachable moment. 1183 01:00:02,290 --> 01:00:08,170 There is a special key word in Python that is literally None, and N-O-N-E, 1184 01:00:08,170 --> 01:00:10,360 with the first letter capitalized. 1185 01:00:10,360 --> 01:00:14,210 This represents officially the absence of a value. 1186 01:00:14,210 --> 01:00:17,440 So I could a little sloppily do something like quote-unquote, 1187 01:00:17,440 --> 01:00:20,410 but does that mean I didn't get around to typing it or not? 1188 01:00:20,410 --> 01:00:24,880 It's a little clear semantically to say literally None, a special keyword 1189 01:00:24,880 --> 01:00:29,620 in Python to make clear that I know Draco has no patronus, 1190 01:00:29,620 --> 01:00:32,320 it's not just an oversight on my part. 1191 01:00:32,320 --> 01:00:36,370 Now that I have this, what do I have in the computer's memory? 1192 01:00:36,370 --> 01:00:37,360 I have a list. 1193 01:00:37,360 --> 01:00:38,620 How do I know it's a list? 1194 01:00:38,620 --> 01:00:42,310 Because I see a square bracket at the beginning and another square bracket 1195 01:00:42,310 --> 01:00:42,850 at the end. 1196 01:00:42,850 --> 01:00:45,730 That's just my visual clue, OK, I don't know necessarily 1197 01:00:45,730 --> 01:00:48,910 what else is going on here, but there's a list of something. 1198 01:00:48,910 --> 01:00:50,960 What is in that list? 1199 01:00:50,960 --> 01:00:53,560 Well, here, too, the syntax is our clue. 1200 01:00:53,560 --> 01:00:57,820 Because this line 2 starts with a curly brace and ends with a curly brace, 1201 01:00:57,820 --> 01:01:02,570 I just know, that is a dictionary, a collection of key value pairs. 1202 01:01:02,570 --> 01:01:04,930 Now this all fit on my screen perfectly, so I 1203 01:01:04,930 --> 01:01:08,020 didn't bother moving all of the key value pairs onto new lines, 1204 01:01:08,020 --> 01:01:11,620 it would have made it really tall, so I kept it all together here this time. 1205 01:01:11,620 --> 01:01:15,520 But how many keys does this first dictionary have? 1206 01:01:15,520 --> 01:01:17,897 Put another way, in Hermione's physical dictionary, 1207 01:01:17,897 --> 01:01:19,480 how many words are in that dictionary? 1208 01:01:19,480 --> 01:01:20,230 Three. 1209 01:01:20,230 --> 01:01:22,990 The words are name, house, and patronus. 1210 01:01:22,990 --> 01:01:26,140 What are the three definitions or values of those words 1211 01:01:26,140 --> 01:01:27,640 in Hermione's dictionary? 1212 01:01:27,640 --> 01:01:31,000 Hermione, Gryffindor, and otter respectively. 1213 01:01:31,000 --> 01:01:35,360 And the same story goes for Harry, then for Ron, 1214 01:01:35,360 --> 01:01:39,190 then for Draco, I have, by design, chosen 1215 01:01:39,190 --> 01:01:44,440 to give them dictionaries that have all the same keys, all the same names, 1216 01:01:44,440 --> 01:01:47,200 but they all have unique values. 1217 01:01:47,200 --> 01:01:50,080 And that's my design, that's my prerogative as a programmer. 1218 01:01:50,080 --> 01:01:53,200 So why is this useful at the end of the day now? 1219 01:01:53,200 --> 01:01:57,130 I have access to a whole collection of interesting data about all 1220 01:01:57,130 --> 01:01:59,620 of these students, and I can still do a loop. 1221 01:01:59,620 --> 01:02:02,980 I can say for students in students, that's 1222 01:02:02,980 --> 01:02:05,590 going to allow me to iterate over this list of students. 1223 01:02:05,590 --> 01:02:08,240 And let me go ahead and print out just one thing at a time. 1224 01:02:08,240 --> 01:02:10,610 Let me print out the current student's name. 1225 01:02:10,610 --> 01:02:14,470 So as complicated as the dictionary is, this should be pretty comfortable. 1226 01:02:14,470 --> 01:02:18,490 For student in students is just going to iterate over every student in the list. 1227 01:02:18,490 --> 01:02:20,420 1, 2, 3, 4 total. 1228 01:02:20,420 --> 01:02:24,580 The next line is just going to print out the value of the name key. 1229 01:02:24,580 --> 01:02:27,850 It's like opening a physical dictionary, looking up the word name, 1230 01:02:27,850 --> 01:02:30,670 and giving us Hermione, Harry, Ron, and Draco 1231 01:02:30,670 --> 01:02:32,480 respectively from each dictionary. 1232 01:02:32,480 --> 01:02:36,880 So if I run this version of Hogwarts and hit Enter, there, I get all three 1233 01:02:36,880 --> 01:02:37,780 of their names. 1234 01:02:37,780 --> 01:02:39,790 But what if I want more information than that? 1235 01:02:39,790 --> 01:02:42,040 I want both their names and their houses. 1236 01:02:42,040 --> 01:02:47,650 Well, just add to print's arguments student, open bracket, house, 1237 01:02:47,650 --> 01:02:48,910 close bracket. 1238 01:02:48,910 --> 01:02:50,740 All right, let's go ahead and run this. 1239 01:02:50,740 --> 01:02:53,170 Python of hogwarts.py and hit Enter. 1240 01:02:53,170 --> 01:02:56,078 So I now see Hermione, Gryffindor; Harry, Gryffindor; and so forth. 1241 01:02:56,078 --> 01:02:58,120 Well, we can aesthetically clean this up a little 1242 01:02:58,120 --> 01:03:01,480 bit by adding a separator with print, like a comma and a space, 1243 01:03:01,480 --> 01:03:03,760 just so that when I run this again, I now 1244 01:03:03,760 --> 01:03:05,680 see some comma separating these values. 1245 01:03:05,680 --> 01:03:08,290 But recall that students have not just a name, not just 1246 01:03:08,290 --> 01:03:09,910 a house, but also that patronus. 1247 01:03:09,910 --> 01:03:12,700 So if we want to print out that, too, we now 1248 01:03:12,700 --> 01:03:18,040 have the syntax via which to go into that same dictionary for each student 1249 01:03:18,040 --> 01:03:22,010 and output their patronus as well as their house in their name. 1250 01:03:22,010 --> 01:03:24,520 So if I run this program one final time, now I 1251 01:03:24,520 --> 01:03:28,490 see all of the data in this here dictionary. 1252 01:03:28,490 --> 01:03:31,390 So this is a lot to absorb all at once, I'm sure. 1253 01:03:31,390 --> 01:03:33,367 It's the last of our new data types. 1254 01:03:33,367 --> 01:03:35,200 On top of lists, we have these dictionaries, 1255 01:03:35,200 --> 01:03:37,750 but again, a dictionary, at the end of the day, 1256 01:03:37,750 --> 01:03:41,740 is just a collection of values similar to these values 1257 01:03:41,740 --> 01:03:44,780 here that allow you to associate keys with values. 1258 01:03:44,780 --> 01:03:48,520 And the first version of this program associated literally the student's 1259 01:03:48,520 --> 01:03:51,040 names with their houses, but then I realized 1260 01:03:51,040 --> 01:03:53,920 in my next version, wait a minute, what if every student has not 1261 01:03:53,920 --> 01:03:55,990 just a name in a house, but a patronus? 1262 01:03:55,990 --> 01:03:59,230 Let's actually standardize the names of our keys 1263 01:03:59,230 --> 01:04:03,850 to be name, house, and patronus, and then the values of those keys 1264 01:04:03,850 --> 01:04:08,530 can actually be the data, like Hermione, Gryffindor, otter, and so forth. 1265 01:04:08,530 --> 01:04:13,240 Questions now on these dictionaries and iteration thereof? 1266 01:04:13,240 --> 01:04:18,710 AUDIENCE: I just was wondering, suppose the dictionary is very huge, 1267 01:04:18,710 --> 01:04:22,270 and if I want to look up for a specific student, 1268 01:04:22,270 --> 01:04:26,650 so how do I know where to look that student from? 1269 01:04:26,650 --> 01:04:29,470 Like can we sort it out in alphabetical order 1270 01:04:29,470 --> 01:04:32,163 or numeric order or anything like that? 1271 01:04:32,163 --> 01:04:33,580 DAVID MALAN: In short answer, yes. 1272 01:04:33,580 --> 01:04:37,570 One of the features of Python is that it makes these dictionaries very highly 1273 01:04:37,570 --> 01:04:38,680 performant for you. 1274 01:04:38,680 --> 01:04:42,280 That is, even if they're very large, as they will be in future weeks 1275 01:04:42,280 --> 01:04:45,910 when we manipulate more data, Python will find the data 1276 01:04:45,910 --> 01:04:48,520 you care about quickly for you. 1277 01:04:48,520 --> 01:04:50,650 And in fact, that is a feature of the language, 1278 01:04:50,650 --> 01:04:53,560 that is a feature of a dictionary to get you the data quickly. 1279 01:04:53,560 --> 01:04:55,480 And there are functions that you can use. 1280 01:04:55,480 --> 01:04:57,550 You can sort the data, you can sift through it, 1281 01:04:57,550 --> 01:05:01,870 you can do very performant operations as we eventually will. 1282 01:05:01,870 --> 01:05:05,800 Allow me, then, to propose, as we wrap up these loops, 1283 01:05:05,800 --> 01:05:08,740 that we solve just a few final problems that will perhaps 1284 01:05:08,740 --> 01:05:11,050 evoke fond memories of yesteryear, at least 1285 01:05:11,050 --> 01:05:13,540 for me, wherein one of my favorite games growing up 1286 01:05:13,540 --> 01:05:15,850 was this one here on the original Nintendo. 1287 01:05:15,850 --> 01:05:19,240 And this is a two-dimensional world where the characters move up, 1288 01:05:19,240 --> 01:05:23,020 down, and right, not so much to the left, in jumping over 1289 01:05:23,020 --> 01:05:25,060 pyramids and obstructions like these. 1290 01:05:25,060 --> 01:05:27,670 And allow me to propose that we use this just for inspiration, 1291 01:05:27,670 --> 01:05:31,180 not to do something that's quite as colorful or graphical as this, but just 1292 01:05:31,180 --> 01:05:34,990 to focus on, for instance, this barrier in the middle of the world 1293 01:05:34,990 --> 01:05:38,080 here that Mario or Luigi had to jump over. 1294 01:05:38,080 --> 01:05:42,372 And so this here seems to be like three bricks stepped on top of one another. 1295 01:05:42,372 --> 01:05:44,080 And we won't do things quite graphically, 1296 01:05:44,080 --> 01:05:48,190 but let's just implement a very simple Python-based version of this textually 1297 01:05:48,190 --> 01:05:50,440 using maybe just hashes for bricks. 1298 01:05:50,440 --> 01:05:53,500 Because there's a pattern here, one on top of the other, and I 1299 01:05:53,500 --> 01:05:56,170 bet we can solve this in any number of ways. 1300 01:05:56,170 --> 01:05:58,720 Well, let me switch back over to VS Code here 1301 01:05:58,720 --> 01:06:03,340 and let me propose that we create a program called mario.py using code 1302 01:06:03,340 --> 01:06:04,750 in the terminal window. 1303 01:06:04,750 --> 01:06:07,630 And then up here, let me start by implementing that same picture 1304 01:06:07,630 --> 01:06:11,590 as simply as I can, printing out just literally the hash, 1305 01:06:11,590 --> 01:06:14,830 and then the hash, and then a third final hash. 1306 01:06:14,830 --> 01:06:17,500 This is going to be a very textual approximation of it, 1307 01:06:17,500 --> 01:06:20,440 but I think if I run Python mario.py, I've 1308 01:06:20,440 --> 01:06:25,840 got a very simple version of that same column of bricks, so to speak. 1309 01:06:25,840 --> 01:06:28,150 But you can imagine that certainly in a game 1310 01:06:28,150 --> 01:06:31,380 where maybe these columns get higher or lower, 1311 01:06:31,380 --> 01:06:33,880 it would be nice to write code that's actually a little more 1312 01:06:33,880 --> 01:06:37,690 dynamic than that and doesn't just use print, print, print, which is literally 1313 01:06:37,690 --> 01:06:39,340 copy and paste, it would seem. 1314 01:06:39,340 --> 01:06:42,550 So let me at least adopt some of today's lessons 1315 01:06:42,550 --> 01:06:44,650 learned and instead do something like this. 1316 01:06:44,650 --> 01:06:50,620 For underscore in range of 3, let's now print out just one of these at a time. 1317 01:06:50,620 --> 01:06:53,230 But the fact that I've now used a 3 to range 1318 01:06:53,230 --> 01:06:55,840 means if I want to change it to something bigger or smaller, 1319 01:06:55,840 --> 01:06:59,350 I change it in one place not in three or more places. 1320 01:06:59,350 --> 01:07:01,450 And this code, too, of course, if I got it right, 1321 01:07:01,450 --> 01:07:05,150 is just going to print out the exact same thing. 1322 01:07:05,150 --> 01:07:06,610 So we're iterating here. 1323 01:07:06,610 --> 01:07:08,860 But let's see if we can't now integrate our discussion 1324 01:07:08,860 --> 01:07:13,420 of writing functions of our own to begin writing something a little more dynamic 1325 01:07:13,420 --> 01:07:16,180 and solving more complicated problems ultimately. 1326 01:07:16,180 --> 01:07:18,130 One of the nice things about functions is 1327 01:07:18,130 --> 01:07:21,550 that they allow us to not just write code that we can use and reuse, 1328 01:07:21,550 --> 01:07:24,640 they allow us to create abstractions, if you will. 1329 01:07:24,640 --> 01:07:28,990 An abstraction is a simplification of a potentially more complicated idea. 1330 01:07:28,990 --> 01:07:31,870 And we've seen this a few times over the course of the weeks. 1331 01:07:31,870 --> 01:07:35,650 For instance, we had a function called hello, which, granted, didn't do 1332 01:07:35,650 --> 01:07:37,480 all that much, it just printed hello. 1333 01:07:37,480 --> 01:07:40,960 But it allowed me to think about the function as exactly what it does, 1334 01:07:40,960 --> 01:07:44,590 not generically printing something, but literally saying hello. 1335 01:07:44,590 --> 01:07:48,520 I've been able to get a number using something similar by defining 1336 01:07:48,520 --> 01:07:50,320 my own function like get number. 1337 01:07:50,320 --> 01:07:53,650 Well let me go ahead and, for instance, assume for the moment 1338 01:07:53,650 --> 01:07:57,160 that I've had the forethought to, in my function main, 1339 01:07:57,160 --> 01:07:59,770 use a function called print column. 1340 01:07:59,770 --> 01:08:03,190 That seems as good a name as any to use a function that 1341 01:08:03,190 --> 01:08:05,290 prints a column of bricks. 1342 01:08:05,290 --> 01:08:07,660 Well, how can I go about now implementing 1343 01:08:07,660 --> 01:08:12,100 this abstraction, this simple idea of print column with actual code? 1344 01:08:12,100 --> 01:08:14,500 Well, we've seen before with def, we can do just that. 1345 01:08:14,500 --> 01:08:16,720 Let me define a function called print column. 1346 01:08:16,720 --> 01:08:21,220 Let me accept as its input, generically speaking, a parameter called height. 1347 01:08:21,220 --> 01:08:25,029 I could call it n or h, but it would be a little more explicit now with height 1348 01:08:25,029 --> 01:08:27,250 just so I remind myself what it's doing. 1349 01:08:27,250 --> 01:08:30,819 And now I think I can just borrow some of that same code from before. 1350 01:08:30,819 --> 01:08:37,990 For underscore n range of height, go ahead and print out a single hash. 1351 01:08:37,990 --> 01:08:41,050 And then at the end of this whole program, let's just call main. 1352 01:08:41,050 --> 01:08:43,120 So I've kind of complicated the code. 1353 01:08:43,120 --> 01:08:45,580 It doesn't do anything more just yet, but it's 1354 01:08:45,580 --> 01:08:48,310 setting me up for solving what I think are going 1355 01:08:48,310 --> 01:08:50,080 to be more sophisticated problems. 1356 01:08:50,080 --> 01:08:53,170 If I run Python of mario.py, we're back where we began. 1357 01:08:53,170 --> 01:08:57,520 But I now have a function, an abstraction, print column, 1358 01:08:57,520 --> 01:09:00,040 that's going to allow me to think about printing 1359 01:09:00,040 --> 01:09:03,432 some chunk of the world of Mario at a time. 1360 01:09:03,432 --> 01:09:05,140 And I can do this in different ways, too. 1361 01:09:05,140 --> 01:09:09,080 Notice that if I really want, I could do something like this. 1362 01:09:09,080 --> 01:09:12,260 I could implement now print column in different ways, 1363 01:09:12,260 --> 01:09:15,260 especially if I am using print column all over my code, 1364 01:09:15,260 --> 01:09:19,220 or maybe still, a colleague of mine, a friend, someone else on the internet 1365 01:09:19,220 --> 01:09:21,200 is using my print column function. 1366 01:09:21,200 --> 01:09:23,899 What's also nice about functions you've written 1367 01:09:23,899 --> 01:09:27,770 is you can change the underlying implementation details of them, 1368 01:09:27,770 --> 01:09:31,850 but so long as you don't change the name of the function or its parameters 1369 01:09:31,850 --> 01:09:35,870 or what it returns, if anything no one else knows the difference. 1370 01:09:35,870 --> 01:09:37,970 You can change the internal implementation 1371 01:09:37,970 --> 01:09:41,760 as much as you want if you want to improve it or make fixes over time. 1372 01:09:41,760 --> 01:09:44,390 So for instance, another way we could implement print column, 1373 01:09:44,390 --> 01:09:46,340 recall, would be something like this. 1374 01:09:46,340 --> 01:09:48,920 A bit clever with one hash and then a new line, 1375 01:09:48,920 --> 01:09:51,750 and then maybe we could do multiplication of strings, 1376 01:09:51,750 --> 01:09:54,080 and then end this line with quote-unquote. 1377 01:09:54,080 --> 01:09:57,110 Again, it's OK if you're not comfortable with this syntax. 1378 01:09:57,110 --> 01:09:59,660 This was a more clever approach we saw in the past. 1379 01:09:59,660 --> 01:10:04,280 But if I run Python of mario.py here, I'll still see a column of three. 1380 01:10:04,280 --> 01:10:07,040 But what's important here is that main does not 1381 01:10:07,040 --> 01:10:12,110 need to know that the underlying implementation of print column 1382 01:10:12,110 --> 01:10:13,980 has changed. 1383 01:10:13,980 --> 01:10:15,980 Well, let's transition to a different dimension, 1384 01:10:15,980 --> 01:10:19,400 if you will, and rather than print out just these vertical bricks, let's 1385 01:10:19,400 --> 01:10:22,160 fast forward in the game to this part of the world here. 1386 01:10:22,160 --> 01:10:25,490 At some part, Mario encounters these bricks in the sky, 1387 01:10:25,490 --> 01:10:27,690 that if he jumps up underneath, they become coins. 1388 01:10:27,690 --> 01:10:29,780 And so he gains to his score. 1389 01:10:29,780 --> 01:10:32,270 But let's go ahead and focus only on those coins, 1390 01:10:32,270 --> 01:10:34,460 and let me propose that we print out, oh, just 1391 01:10:34,460 --> 01:10:36,110 these four question marks here. 1392 01:10:36,110 --> 01:10:38,150 And let me go back to VS Code here. 1393 01:10:38,150 --> 01:10:41,480 And let me propose that within VS Code here, just like before, we 1394 01:10:41,480 --> 01:10:43,010 try to abstract this away. 1395 01:10:43,010 --> 01:10:45,290 So let me go ahead and get rid of this version, 1396 01:10:45,290 --> 01:10:49,520 because we're now going horizontal instead of vertical with our output. 1397 01:10:49,520 --> 01:10:53,690 And let me just say, well, print row four times. 1398 01:10:53,690 --> 01:10:56,360 Let me just abstract away the problem at hand. 1399 01:10:56,360 --> 01:10:59,180 I don't know yet how I'm going to print those four question marks, 1400 01:10:59,180 --> 01:11:03,770 but let's call it print row 4, and I'll assume I'll now solve this problem. 1401 01:11:03,770 --> 01:11:06,800 Let's now go down that rabbit hole of solving the problem. 1402 01:11:06,800 --> 01:11:09,020 Define a function called print row. 1403 01:11:09,020 --> 01:11:11,570 It's going to take a width instead of a height, 1404 01:11:11,570 --> 01:11:14,030 because it's horizontal instead of vertical. 1405 01:11:14,030 --> 01:11:15,750 And how can I do this? 1406 01:11:15,750 --> 01:11:19,160 Well now, we have an opportunity to do string multiplication even more 1407 01:11:19,160 --> 01:11:19,760 elegantly. 1408 01:11:19,760 --> 01:11:23,300 I can say quote-unquote, question mark, times width. 1409 01:11:23,300 --> 01:11:28,010 And this is a very pretty Pythonic way of printing what could otherwise 1410 01:11:28,010 --> 01:11:29,990 be a loop, and that's fine, but this is going 1411 01:11:29,990 --> 01:11:32,630 to go ahead and print those question marks for me. 1412 01:11:32,630 --> 01:11:37,130 Let's do Python of mario.py, Enter, and now I've got four question marks. 1413 01:11:37,130 --> 01:11:39,530 It's not nearly as pretty as the more graphical version, 1414 01:11:39,530 --> 01:11:44,390 but it is at least a building block toward having 1415 01:11:44,390 --> 01:11:47,870 now a reusable function like print row. 1416 01:11:47,870 --> 01:11:49,130 And why am I doing all this? 1417 01:11:49,130 --> 01:11:52,820 Like why are we over engineering the solution to these problems 1418 01:11:52,820 --> 01:11:54,920 by having print column and print row? 1419 01:11:54,920 --> 01:11:57,620 Well, it's a useful problem-solving technique. 1420 01:11:57,620 --> 01:12:00,410 As soon as your world does not look one-dimensional 1421 01:12:00,410 --> 01:12:04,130 like this or with the column version, but what about this? 1422 01:12:04,130 --> 01:12:08,270 Later in Super Mario Brothers does Mario have to jump down into this world 1423 01:12:08,270 --> 01:12:11,000 where there's a lot of these underworld barriers. 1424 01:12:11,000 --> 01:12:13,400 And this one here, for instance, looks like a square. 1425 01:12:13,400 --> 01:12:16,400 It's two-dimensional there's a height and a width to it. 1426 01:12:16,400 --> 01:12:18,830 And that is to say there's a bunch of different ways 1427 01:12:18,830 --> 01:12:21,980 we could implement this thing if, maybe for discussion, 1428 01:12:21,980 --> 01:12:26,780 it's like a 3-by-3 grid, a 3-by-3 square of sorts. 1429 01:12:26,780 --> 01:12:29,570 Well, how can we go about solving this here problem? 1430 01:12:29,570 --> 01:12:32,060 Well, let me propose we come back to VS Code 1431 01:12:32,060 --> 01:12:36,420 and let me propose that we think about this in a couple of different ways. 1432 01:12:36,420 --> 01:12:39,740 I could do this like this. 1433 01:12:39,740 --> 01:12:44,450 If I know where I'm going, maybe I'm a seasoned programmer, let me go ahead 1434 01:12:44,450 --> 01:12:45,060 and do this. 1435 01:12:45,060 --> 01:12:48,530 Let me print out a square, the width, and the height of which is 3. 1436 01:12:48,530 --> 01:12:49,487 That's an abstraction. 1437 01:12:49,487 --> 01:12:52,070 I'm just taking for granted for a moment that there is already 1438 01:12:52,070 --> 01:12:56,180 a function called print square that's going to be with 3 and height 3 1439 01:12:56,180 --> 01:12:57,068 as well. 1440 01:12:57,068 --> 01:12:59,360 But someone's got to implement this, and at the moment, 1441 01:12:59,360 --> 01:13:01,580 there's only me at the keyboard, so let's go ahead 1442 01:13:01,580 --> 01:13:03,020 and implement that square. 1443 01:13:03,020 --> 01:13:05,000 Let me go ahead and define a function called 1444 01:13:05,000 --> 01:13:10,250 print square that takes in a specific size, both for height and for width. 1445 01:13:10,250 --> 01:13:13,310 And here's where we have an opportunity to use some of those loops. 1446 01:13:13,310 --> 01:13:16,250 And we can use those loops in a way we haven't yet. 1447 01:13:16,250 --> 01:13:21,500 If I want to print out all of these rows, but also, all of these columns, 1448 01:13:21,500 --> 01:13:24,620 I now have to think not just cyclically like a loop allows, 1449 01:13:24,620 --> 01:13:26,960 but I need to think two-dimensionally. 1450 01:13:26,960 --> 01:13:30,560 And if you're familiar with like an old school typewriter or even a printer 1451 01:13:30,560 --> 01:13:33,570 nowadays, it generally prints from top to bottom. 1452 01:13:33,570 --> 01:13:38,550 So even if you have multiple columns, you print out one line at a time, 1453 01:13:38,550 --> 01:13:41,360 and while you're on that line, the printer or the typewriter 1454 01:13:41,360 --> 01:13:42,750 prints from left to right. 1455 01:13:42,750 --> 01:13:46,550 And that's the mental model to have with your black and white terminal window. 1456 01:13:46,550 --> 01:13:50,810 All of the output for every example thus far starts at the top 1457 01:13:50,810 --> 01:13:52,340 and goes down to the bottom. 1458 01:13:52,340 --> 01:13:54,120 From top to bottom, left to right. 1459 01:13:54,120 --> 01:13:58,770 So we have to generate our output, our square in that same way. 1460 01:13:58,770 --> 01:14:01,070 So let me propose that we do this. 1461 01:14:01,070 --> 01:14:04,790 Let me propose that we know we need to iterate this many times, 3 or more 1462 01:14:04,790 --> 01:14:05,810 generally size. 1463 01:14:05,810 --> 01:14:06,560 So let me do this. 1464 01:14:06,560 --> 01:14:12,200 For i in the range of size, what do I need to do three times? 1465 01:14:12,200 --> 01:14:14,520 Well, I want to print out what? 1466 01:14:14,520 --> 01:14:17,790 1, 2, 3 rows of bricks. 1467 01:14:17,790 --> 01:14:20,850 But within each row of bricks, what do I want to print? 1468 01:14:20,850 --> 01:14:24,220 1, 2, 3 bricks specifically. 1469 01:14:24,220 --> 01:14:26,790 So if we go back to our diagram here and I 1470 01:14:26,790 --> 01:14:33,700 stipulate that it's indeed meant to be a 3-by-3 square, 3 wide and 3 tall, 1471 01:14:33,700 --> 01:14:35,880 what did I want to do to print the first row? 1472 01:14:35,880 --> 01:14:40,095 I want to print brick brick, brick. 1473 01:14:40,095 --> 01:14:42,720 What do I want to print on the second row? brick, brick, brick. 1474 01:14:42,720 --> 01:14:44,580 And the third row, brick, brick, brick. 1475 01:14:44,580 --> 01:14:48,390 So I'm doing three things three times. 1476 01:14:48,390 --> 01:14:50,650 There's a lot of printing that must happen. 1477 01:14:50,650 --> 01:14:53,670 So let me go back to my code here and let me propose now 1478 01:14:53,670 --> 01:14:57,540 that we think of this outer loop that I've just started 1479 01:14:57,540 --> 01:15:00,960 as representing each of our rows. 1480 01:15:00,960 --> 01:15:04,950 For i in range of size is going to ensure, no matter 1481 01:15:04,950 --> 01:15:10,920 what I do next, that I can print out 1, 2, 3 rows, or more generally, 1482 01:15:10,920 --> 01:15:15,030 size, where size could be 3, but it could be smaller or larger. 1483 01:15:15,030 --> 01:15:17,520 What do I want to do on each of the rows? 1484 01:15:17,520 --> 01:15:21,270 Well, just like an old school typewriter or printer, on each row, 1485 01:15:21,270 --> 01:15:24,420 I want to print out brick, brick, brick; brick, brick, brick; brick, brick, 1486 01:15:24,420 --> 01:15:25,470 brick. 1487 01:15:25,470 --> 01:15:28,260 Well, that sounds like a cycle, some kind of loop. 1488 01:15:28,260 --> 01:15:31,740 So maybe I can have inside of one loop another loop. 1489 01:15:31,740 --> 01:15:35,100 I don't want to use i again because I don't want to use the same variable 1490 01:15:35,100 --> 01:15:36,450 and mess up my counting. 1491 01:15:36,450 --> 01:15:38,860 So I'm going to by convention use j. 1492 01:15:38,860 --> 01:15:41,460 Very common to use i and then j-- maybe k, 1493 01:15:41,460 --> 01:15:44,800 but after that, you shouldn't keep nesting inside of each other. 1494 01:15:44,800 --> 01:15:47,790 Let me go ahead and say for j in range of size 2, 1495 01:15:47,790 --> 01:15:50,940 because it's a square, and then each of these rows, 1496 01:15:50,940 --> 01:15:57,660 let me print out a single hash, but no new line, but after each row, 1497 01:15:57,660 --> 01:16:00,750 let me print only a new line. 1498 01:16:00,750 --> 01:16:03,720 So there's a lot going on here, especially if you've never 1499 01:16:03,720 --> 01:16:08,220 touched Python, let alone loops, but notice what I've done here, too, 1500 01:16:08,220 --> 01:16:10,800 and I'll add some comments for clarity. 1501 01:16:10,800 --> 01:16:22,300 For each row in square, for each brick in row, print brick. 1502 01:16:22,300 --> 01:16:25,330 And here is where comments, and more generally, 1503 01:16:25,330 --> 01:16:28,990 pseudocode can really help explain to yourself and to others 1504 01:16:28,990 --> 01:16:30,820 what your lines of code are doing. 1505 01:16:30,820 --> 01:16:35,410 On line 8, I'm iterating from i equals 0 on up to size. 1506 01:16:35,410 --> 01:16:37,180 So 0, 1, 2. 1507 01:16:37,180 --> 01:16:41,560 On line 11, I'm doing the exact same thing, but using j from 0, 1, 2. 1508 01:16:41,560 --> 01:16:45,490 But that's good, because i represents how each of my rows. 1509 01:16:45,490 --> 01:16:49,300 And while I'm on each of those rows, inside of this outer loop, 1510 01:16:49,300 --> 01:16:53,110 I'm going to do brick, brick, brick; 1, 2, 3; 1, 2, 3; 1, 2, 3. 1511 01:16:53,110 --> 01:16:56,830 But I don't want my cursor to keep moving to the next line 1512 01:16:56,830 --> 01:17:01,260 while I'm on a row, so I'm just overriding that line ending. 1513 01:17:01,260 --> 01:17:03,010 But let me ask you a question of the group 1514 01:17:03,010 --> 01:17:10,160 now, why on line 16 do I have a print here all by itself? 1515 01:17:10,160 --> 01:17:13,820 Why do I have a print all by itself? 1516 01:17:13,820 --> 01:17:19,180 Notice that it's below the inner loop, but inside 1517 01:17:19,180 --> 01:17:22,300 of the outer loop, so to speak. 1518 01:17:22,300 --> 01:17:26,650 What is that loop on line 16 doing ultimately? 1519 01:17:26,650 --> 01:17:29,080 AUDIENCE: Every time you finish a line, you 1520 01:17:29,080 --> 01:17:33,490 have to add a new line at the end of it. 1521 01:17:33,490 --> 01:17:36,905 So print, it prints a new line. 1522 01:17:36,905 --> 01:17:37,780 DAVID MALAN: Perfect. 1523 01:17:37,780 --> 01:17:40,330 I don't want a new line after every brick. 1524 01:17:40,330 --> 01:17:42,670 I only want to do that at the end of the row, 1525 01:17:42,670 --> 01:17:45,460 and that's why my comments now are perhaps enlightening. 1526 01:17:45,460 --> 01:17:51,460 Notice that this loop here is just iterating for each brick in the row. 1527 01:17:51,460 --> 01:17:54,190 Once I'm done with that inner loop, so to speak, 1528 01:17:54,190 --> 01:17:57,760 once I'm done with these highlighted lines here, to Evelyn's point, 1529 01:17:57,760 --> 01:17:59,927 I need to print out one blank new line. 1530 01:17:59,927 --> 01:18:03,010 And we've not done this before, but when you call print with no arguments, 1531 01:18:03,010 --> 01:18:05,770 all you get is that automatic line ending, 1532 01:18:05,770 --> 01:18:09,110 the backslash n where the cursor moves to the next line. 1533 01:18:09,110 --> 01:18:13,540 So if I now go back to my terminal window and run mario.py, 1534 01:18:13,540 --> 01:18:16,653 I think I should get a 3-by-3 square. 1535 01:18:16,653 --> 01:18:18,820 And it doesn't quite look like a square on my screen 1536 01:18:18,820 --> 01:18:22,300 because these hashes are a little taller than they are wide, but it is, in fact, 1537 01:18:22,300 --> 01:18:23,680 3-by-3. 1538 01:18:23,680 --> 01:18:26,140 But let me propose, as we've always done here, how 1539 01:18:26,140 --> 01:18:28,030 we might tighten up this code further. 1540 01:18:28,030 --> 01:18:32,050 Just for clarity's sake, let me get rid of my comments for a moment 1541 01:18:32,050 --> 01:18:35,680 just so we can see how many lines of code we have total. 1542 01:18:35,680 --> 01:18:39,040 And let me propose that we maybe do this. 1543 01:18:39,040 --> 01:18:41,737 Let me propose that, you know what, this inner loop, 1544 01:18:41,737 --> 01:18:43,570 especially if you're having trouble wrapping 1545 01:18:43,570 --> 01:18:46,360 your mind around one loop inside of another loop, 1546 01:18:46,360 --> 01:18:47,710 you don't strictly need it. 1547 01:18:47,710 --> 01:18:49,270 What if we do this trick again? 1548 01:18:49,270 --> 01:18:54,130 What if we print out inside of the outer and only loop each 1549 01:18:54,130 --> 01:18:57,910 of those hashes times the number of times we want them? 1550 01:18:57,910 --> 01:19:00,400 We draw inspiration from an earlier approach 1551 01:19:00,400 --> 01:19:03,980 and we run Python now of mario.py, same result, 1552 01:19:03,980 --> 01:19:07,480 but now, print square is really nice and compact. 1553 01:19:07,480 --> 01:19:10,810 It has one explicit loop, and it's still printing out 1554 01:19:10,810 --> 01:19:15,340 using string multiplication all of the hashes at once on that row. 1555 01:19:15,340 --> 01:19:19,600 If you like abstraction and you'd like to wrap your mind more around what 1556 01:19:19,600 --> 01:19:21,580 the code is doing, well, let's do this. 1557 01:19:21,580 --> 01:19:23,770 If you're not quite clear on what's going on, 1558 01:19:23,770 --> 01:19:25,870 let's propose that you implement a function called 1559 01:19:25,870 --> 01:19:28,150 print row, passing in size. 1560 01:19:28,150 --> 01:19:33,850 And let me propose that this print row function, it simply take in that width 1561 01:19:33,850 --> 01:19:39,260 and print out the individual hash times that many times. 1562 01:19:39,260 --> 01:19:43,870 In other words, here's an opportunity for abstraction, whereby, well, what 1563 01:19:43,870 --> 01:19:45,157 does it mean to print a row? 1564 01:19:45,157 --> 01:19:46,990 Well, when you're implementing print square, 1565 01:19:46,990 --> 01:19:49,720 I don't really care what it means to print a row, 1566 01:19:49,720 --> 01:19:53,440 I just need to know that someone's taking care of printing the row. 1567 01:19:53,440 --> 01:19:56,740 You can pass the buck to another function altogether. 1568 01:19:56,740 --> 01:19:58,360 And how does print row work? 1569 01:19:58,360 --> 01:20:02,500 Well, it could use a for loop, it could use this string multiplication trick. 1570 01:20:02,500 --> 01:20:05,980 This is a way to take a larger program-- and this is probably the most 1571 01:20:05,980 --> 01:20:08,120 complicated one we've looked at thus far-- 1572 01:20:08,120 --> 01:20:13,600 and to decompose it into these smaller components, that once assembled, 1573 01:20:13,600 --> 01:20:16,390 achieve your final idea. 1574 01:20:16,390 --> 01:20:19,780 Seeing no questions, that's the end of our look at loops 1575 01:20:19,780 --> 01:20:22,900 in Python, this ability to do things cyclically again and again, 1576 01:20:22,900 --> 01:20:25,480 and when we combine those with conditionals, this ability 1577 01:20:25,480 --> 01:20:28,870 to ask and answer questions and combine them with our functions and variables, 1578 01:20:28,870 --> 01:20:31,450 we really now have most of the building blocks 1579 01:20:31,450 --> 01:20:34,060 we need to solve much larger, much more interesting, much 1580 01:20:34,060 --> 01:20:35,260 more personal questions. 1581 01:20:35,260 --> 01:20:39,100 So in the weeks to come, we'll start to see exactly what could go wrong, 1582 01:20:39,100 --> 01:20:41,080 though, when we do so, but we'll introduce you 1583 01:20:41,080 --> 01:20:45,600 to all the more tools via which you can troubleshoot those same problems. 1584 01:20:45,600 --> 01:20:47,000