WEBVTT X-TIMESTAMP-MAP=LOCAL:00:00:00.000,MPEGTS:900000 00:00:00.000 --> 00:00:03.451 [MUSIC PLAYING] 00:00:24.160 --> 00:00:25.180 DAVID MALAN: All right. 00:00:25.180 --> 00:00:28.540 This is CS50's Introduction to Programming with Python. 00:00:28.540 --> 00:00:33.010 My name is David Malan, and this week we focus on loops, this ability in Python 00:00:33.010 --> 00:00:37.000 and a lot of other programming languages to do something again and again, 00:00:37.000 --> 00:00:38.500 a cycle of sorts. 00:00:38.500 --> 00:00:40.420 And let's see if we can't begin by motivating 00:00:40.420 --> 00:00:45.310 exactly why we have this ability to do things cyclically using these loops. 00:00:45.310 --> 00:00:48.130 I'm going to go ahead here and open up VS Code. 00:00:48.130 --> 00:00:50.260 And in my terminal window, let's go ahead 00:00:50.260 --> 00:00:57.100 and create via code cat.py, a Python program that meows like a cat. 00:00:57.100 --> 00:01:00.910 And I'm going to go ahead here in this Code tab, and very simply, perhaps, 00:01:00.910 --> 00:01:03.760 I'm going to start by implementing this cat just by using print. 00:01:03.760 --> 00:01:06.010 We're going to have this cat not make audible sounds, 00:01:06.010 --> 00:01:08.860 but just print meow, meow, meow on the screen three times. 00:01:08.860 --> 00:01:12.640 Well, I think the simplest way I can do this is just to print meow once, 00:01:12.640 --> 00:01:18.590 and to print meow again, and to print meow one last time on the screen. 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, 00:01:23.320 --> 00:01:25.480 Enter, and meow, meow, meow. 00:01:25.480 --> 00:01:27.670 All right, so this program works. 00:01:27.670 --> 00:01:31.120 This program indeed works if my goal is to get the cat to meow three times. 00:01:31.120 --> 00:01:34.280 And let me propose, just to help us wrap our minds around 00:01:34.280 --> 00:01:36.430 what's going on inside of the computer, let 00:01:36.430 --> 00:01:38.810 me propose that we consider this flowchart. 00:01:38.810 --> 00:01:40.810 So as before, we have this flowchart that 00:01:40.810 --> 00:01:44.140 starts with this oval, which just means start reading here. 00:01:44.140 --> 00:01:50.050 And then notice, it goes via arrows to a meow, meow, meow, and then it stops. 00:01:50.050 --> 00:01:53.890 It's perfectly correct, and honestly, it's wonderfully simple, 00:01:53.890 --> 00:01:58.090 but I daresay we can find fault with my code nonetheless. 00:01:58.090 --> 00:02:03.550 Why is my code arguably poorly designed? 00:02:03.550 --> 00:02:05.680 Now the answer is going to be loops in some way, 00:02:05.680 --> 00:02:08.169 but let's see if we can identify in what way 00:02:08.169 --> 00:02:12.950 the code is actually poorly designed in some sense. 00:02:12.950 --> 00:02:13.660 Let's see. 00:02:13.660 --> 00:02:14.260 Any thoughts. 00:02:14.260 --> 00:02:15.608 Alex? 00:02:15.608 --> 00:02:16.150 AUDIENCE: OK. 00:02:16.150 --> 00:02:21.580 So, I mean, repeating the same action like three times or even more 00:02:21.580 --> 00:02:23.095 is not a good habit. 00:02:23.095 --> 00:02:24.970 DAVID MALAN: Yeah, I'm just repeating myself. 00:02:24.970 --> 00:02:27.340 And honestly, it's not that big a deal. 00:02:27.340 --> 00:02:31.780 If we go back to my code here, am I really doing such a bad thing 00:02:31.780 --> 00:02:34.180 by just printing meow, meow, meow three times? 00:02:34.180 --> 00:02:37.250 Not really, but let's consider the logical extension of this. 00:02:37.250 --> 00:02:43.510 Suppose I wanted to meow four times or five times or 50 times or 500 times. 00:02:43.510 --> 00:02:46.150 Do you really think, even if you've never programmed before, 00:02:46.150 --> 00:02:50.350 is the solution to this problem really going to be to hit copy-paste 50 times? 00:02:50.350 --> 00:02:51.310 Like probably not. 00:02:51.310 --> 00:02:52.840 We can probably do better than that. 00:02:52.840 --> 00:02:54.850 And beyond it just being ugly at that point, 00:02:54.850 --> 00:02:57.732 having so many lines of identical code, just 00:02:57.732 --> 00:02:59.440 imagine if you wanted to change the code. 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. 00:03:02.607 --> 00:03:04.930 So now it has to say woof, woof, woof multiple times. 00:03:04.930 --> 00:03:07.780 Now I have to change that in 50 different places. 00:03:07.780 --> 00:03:10.030 And yeah, sure, I could do find and replace, 00:03:10.030 --> 00:03:12.070 but come on, like we're programmers now, there's 00:03:12.070 --> 00:03:15.080 got to be a better way than just repeating ourselves. 00:03:15.080 --> 00:03:18.400 So I bet we can do better than that if we think about a little 00:03:18.400 --> 00:03:22.960 harder how we go about structuring this program. 00:03:22.960 --> 00:03:26.750 And we can do that if we augment our vocabulary just a little bit. 00:03:26.750 --> 00:03:28.870 It turns out in Python, and in other languages, 00:03:28.870 --> 00:03:31.270 too, there's a keyword called while. 00:03:31.270 --> 00:03:34.960 And while is one way that we can express what's called a loop, 00:03:34.960 --> 00:03:38.530 a block of code that's going to do something again and again and again-- 00:03:38.530 --> 00:03:43.480 0 times, 1 time, 2 times, 50 times, as many times as we want. 00:03:43.480 --> 00:03:48.520 But while rather leaves to us the particulars 00:03:48.520 --> 00:03:52.010 of how we express ourselves to do something again and again. 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. 00:03:56.260 --> 00:04:01.765 While is a construct that allows me to ask a question again and again. 00:04:01.765 --> 00:04:03.640 And any time we've seen a question, it's been 00:04:03.640 --> 00:04:07.180 in the form of a Boolean expression, a question to which the answer is 00:04:07.180 --> 00:04:08.900 true or false. 00:04:08.900 --> 00:04:10.250 Well, how could I do this? 00:04:10.250 --> 00:04:15.340 How could I print out meow three times and ask three times a question 00:04:15.340 --> 00:04:18.079 to which the answer is true or false? 00:04:18.079 --> 00:04:20.110 Well, what if I did some counting? 00:04:20.110 --> 00:04:21.560 Like literally on my fingers. 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, 00:04:25.360 --> 00:04:28.060 I can put three fingers up and I can meow. 00:04:28.060 --> 00:04:31.342 And then I can put like one of the fingers down and then meow. 00:04:31.342 --> 00:04:33.550 And I can put one of the fingers down and I can meow. 00:04:33.550 --> 00:04:34.870 Put one of the fingers down. 00:04:34.870 --> 00:04:38.200 And maybe the question I can ask every time I meow 00:04:38.200 --> 00:04:40.840 is, do I have any fingers up still? 00:04:40.840 --> 00:04:42.370 Do I have any fingers up still? 00:04:42.370 --> 00:04:43.662 Do I have any fingers up still? 00:04:43.662 --> 00:04:45.490 And if the answer is true, keep going. 00:04:45.490 --> 00:04:48.040 If the answer is false, stop. 00:04:48.040 --> 00:04:50.710 So how can I translate that to code? 00:04:50.710 --> 00:04:53.020 Well, once we've added this while keyword-- 00:04:53.020 --> 00:04:57.590 I think we have all the building blocks already, let me propose that I do this. 00:04:57.590 --> 00:04:59.860 Let me propose that I give myself a variable. 00:04:59.860 --> 00:05:02.740 And I'll call it i for integer, but I could call it anything I want, 00:05:02.740 --> 00:05:04.780 and I'm going to initialize it to 3. 00:05:04.780 --> 00:05:07.780 Then I'm going to use this new feature of Python, while, 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. 00:05:12.380 --> 00:05:17.470 And I'm going to say, while i does not equal 0. 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. 00:05:22.630 --> 00:05:24.760 Notice the colon at the end of the line. 00:05:24.760 --> 00:05:25.890 Notice my indentation. 00:05:25.890 --> 00:05:28.470 And just like with functions, just like with conditionals, 00:05:28.470 --> 00:05:34.440 you indent the lines that you only want to execute as part of this other thing. 00:05:34.440 --> 00:05:37.920 What do I want to do while i does not equal 0? 00:05:37.920 --> 00:05:41.130 Well, I think I just want to meow. 00:05:41.130 --> 00:05:44.820 But it's not enough just to write this code. 00:05:44.820 --> 00:05:52.380 If I were to very dangerously run Python of cat.py and hit Enter right now, 00:05:52.380 --> 00:05:55.560 what might happen on the screen? 00:05:55.560 --> 00:05:58.320 Whether you've programmed before or not. 00:05:58.320 --> 00:06:01.200 Why is this a very bad thing potentially? 00:06:01.200 --> 00:06:05.700 It's not going to break things, but it might lose control of my computer 00:06:05.700 --> 00:06:07.270 somehow. 00:06:07.270 --> 00:06:08.620 Any thoughts? 00:06:08.620 --> 00:06:10.120 Yeah, Timo? 00:06:10.120 --> 00:06:11.020 AUDIENCE: Hi. 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 00:06:18.790 --> 00:06:20.995 and the while is always true. 00:06:20.995 --> 00:06:22.120 DAVID MALAN: Yeah, exactly. 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, 00:06:26.320 --> 00:06:29.440 then I'm asking the question, while i does not equal 0, 00:06:29.440 --> 00:06:31.810 and that's going to be true, it does not equal 0, 00:06:31.810 --> 00:06:34.240 it obviously equals 3, print meow. 00:06:34.240 --> 00:06:38.950 And the way a while loop works is that the Python interpreter just 00:06:38.950 --> 00:06:40.480 keeps going back and forth. 00:06:40.480 --> 00:06:45.310 It goes from line 1 to line 2, then to line 3, 00:06:45.310 --> 00:06:48.490 and then it goes back to line 2 to ask the question again. 00:06:48.490 --> 00:06:50.950 If the answer is still true, it goes to line 3. 00:06:50.950 --> 00:06:52.420 It then goes back to line 2. 00:06:52.420 --> 00:06:55.090 If the answer is still true, it goes back to line 3. 00:06:55.090 --> 00:07:00.100 And to Timo's point, if you're never actually changing the value of i, 00:07:00.100 --> 00:07:04.450 it's always 3, you're just going to be looping literally forever, 00:07:04.450 --> 00:07:07.028 and this is an accidental infinite loop. 00:07:07.028 --> 00:07:08.570 So we've got to be smarter than that. 00:07:08.570 --> 00:07:09.820 And I'm not going to hit Enter because I don't 00:07:09.820 --> 00:07:12.195 want to lose control over my computer here such that it's 00:07:12.195 --> 00:07:14.080 printing out meow forever. 00:07:14.080 --> 00:07:16.960 Fortunately, if you ever do do that and you find yourself 00:07:16.960 --> 00:07:21.940 in an accidental infinite loop, Control-C for cancel or interrupt 00:07:21.940 --> 00:07:23.110 is going to be your friend. 00:07:23.110 --> 00:07:26.110 If you ever seem to lose control, you don't need to reboot 00:07:26.110 --> 00:07:27.520 or turn off the computer. 00:07:27.520 --> 00:07:30.430 You can just hit Control-C in your terminal window 00:07:30.430 --> 00:07:32.560 and that will likely fix it. 00:07:32.560 --> 00:07:35.920 All right, well what do I want to do, then, after meowing each time? 00:07:35.920 --> 00:07:39.820 I think what I'd like to do here is maybe something like this. 00:07:39.820 --> 00:07:46.750 Let me update i to equal whatever the current value is minus 1 here-- 00:07:46.750 --> 00:07:47.530 whoops, sorry. 00:07:47.530 --> 00:07:48.820 Minus 1. 00:07:48.820 --> 00:07:51.310 So if i on each iteration-- 00:07:51.310 --> 00:07:55.090 I'm updating i to be one less, one less, one less, 00:07:55.090 --> 00:08:00.610 it should eventually hit 0, at which point the answer to 9.2's question 00:08:00.610 --> 00:08:02.540 will now be false. 00:08:02.540 --> 00:08:03.770 So let's see if this works. 00:08:03.770 --> 00:08:06.790 I'm going to go down to my terminal window and run Python of cat.py, 00:08:06.790 --> 00:08:09.700 and I indeed get three meows. 00:08:09.700 --> 00:08:10.360 Why? 00:08:10.360 --> 00:08:14.230 Because I've wired this up like a machine in software, if you will. 00:08:14.230 --> 00:08:17.360 I've set i equal to 3, then I keep asking this question. 00:08:17.360 --> 00:08:21.940 But I keep turning the gears, I keep changing the value of the variable 00:08:21.940 --> 00:08:25.180 to make sure that ultimately it is actually 00:08:25.180 --> 00:08:30.468 being decremented-- that is, decreased by 1 until we eventually hit 0. 00:08:30.468 --> 00:08:33.010 Now for those of you who think I'm a little more graphically, 00:08:33.010 --> 00:08:35.110 let me pull up one of our usual flow charts. 00:08:35.110 --> 00:08:38.610 This is just a representation graphically of the exact same thing. 00:08:38.610 --> 00:08:39.610 Notice what's happening. 00:08:39.610 --> 00:08:44.020 I first start the program, and then I initialize i to 3, 00:08:44.020 --> 00:08:46.300 and then I ask the first of my questions. 00:08:46.300 --> 00:08:48.577 Again, the diamonds always represent questions. 00:08:48.577 --> 00:08:50.410 And the answer is going to be true or false. 00:08:50.410 --> 00:08:52.690 Does i not equal 0? 00:08:52.690 --> 00:08:54.190 Well, it doesn't, it equals 3. 00:08:54.190 --> 00:08:56.710 So if I follow the true line, I meow. 00:08:56.710 --> 00:09:01.690 And then I follow this arrow, and I update i to equal i minus 1. 00:09:01.690 --> 00:09:05.200 At this point in the story, i presumably equals 2 mathematically. 00:09:05.200 --> 00:09:06.400 I follow the arrow. 00:09:06.400 --> 00:09:07.483 And there's the loop. 00:09:07.483 --> 00:09:09.400 This is why it's nice to see this graphically, 00:09:09.400 --> 00:09:12.770 perhaps because you can literally see the loop back and forth. 00:09:12.770 --> 00:09:14.240 Now I ask the question again. 00:09:14.240 --> 00:09:16.270 Does 2 not equal 0? 00:09:16.270 --> 00:09:20.060 Well, it does not equal 0, it's 2, so we meow again. 00:09:20.060 --> 00:09:21.940 We change i from 2 to 1. 00:09:21.940 --> 00:09:23.770 Well, does 1 not equal 0? 00:09:23.770 --> 00:09:27.490 Well obviously 1 is not 0, so we meow again. 00:09:27.490 --> 00:09:30.580 We decrement i again. i is now 0. 00:09:30.580 --> 00:09:33.070 Does 0 not equal 0? 00:09:33.070 --> 00:09:37.930 No, it equals 0, so the answer is false and we stop. 00:09:37.930 --> 00:09:41.260 So there, perhaps more so than any of our flowcharts before, 00:09:41.260 --> 00:09:45.295 do you really see the structure of what's happening inside of the program? 00:09:45.295 --> 00:09:47.920 And you don't have to get into the habit of making these charts 00:09:47.920 --> 00:09:50.830 or creating these charts, but just as a first pass at what's 00:09:50.830 --> 00:09:55.010 going on inside of the computer, that's indeed one way to visualize it instead. 00:09:55.010 --> 00:09:57.760 Well let me propose that, like always, there's many different ways 00:09:57.760 --> 00:09:58.690 to solve this problem. 00:09:58.690 --> 00:10:01.023 And suppose you just like to think a little differently. 00:10:01.023 --> 00:10:04.700 Maybe you don't like starting at 3 and then counting down to 0. 00:10:04.700 --> 00:10:05.200 Why? 00:10:05.200 --> 00:10:07.075 Maybe you're just brain doesn't work that way 00:10:07.075 --> 00:10:09.100 and you prefer to count up instead of down. 00:10:09.100 --> 00:10:10.400 Totally fine. 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. 00:10:15.700 --> 00:10:18.040 And here, let me just change my logic. 00:10:18.040 --> 00:10:20.500 Rather than checking for not equal to 0, like maybe 00:10:20.500 --> 00:10:23.500 you don't like thinking in terms of not because it's a little confusing, 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. 00:10:28.720 --> 00:10:30.310 So we'll be a little more explicit. 00:10:30.310 --> 00:10:34.690 We'll count from 1 up through 3, each time printing meow, 00:10:34.690 --> 00:10:36.970 but I'm going to need to change this line here. 00:10:36.970 --> 00:10:40.240 Let me see if we can't call on someone to change line for me. 00:10:40.240 --> 00:10:47.560 How do I want to change line 4 to be consistent with counting from 1 up 00:10:47.560 --> 00:10:52.080 to and through 3? 00:10:52.080 --> 00:10:57.465 AUDIENCE: I would be plus 1 every time you meow. 00:10:57.465 --> 00:10:58.590 DAVID MALAN: Yeah, exactly. 00:10:58.590 --> 00:11:01.800 In this case, we want to add one not subtract 1. 00:11:01.800 --> 00:11:05.460 And in fact, if you think about this, this 2 could end very poorly. 00:11:05.460 --> 00:11:09.630 If you start counting at 1 and you keep subtracting 1, subtracting 1, 00:11:09.630 --> 00:11:11.850 subtracting 1, I think we're going to find ourselves 00:11:11.850 --> 00:11:15.780 with the same problem, which is that we're never going to stop because we're 00:11:15.780 --> 00:11:19.140 going to keep getting more and more negative as opposed to ever getting up 00:11:19.140 --> 00:11:20.160 to the number 3. 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. 00:11:24.660 --> 00:11:27.840 And now notice just for clarity, too, the equal sign 00:11:27.840 --> 00:11:30.810 is, again, our assignment operator from right to left. 00:11:30.810 --> 00:11:33.150 Logically, this might otherwise strike you as strange. 00:11:33.150 --> 00:11:35.880 Like how can i equal itself plus 1? 00:11:35.880 --> 00:11:39.720 Well, it doesn't until you execute this code from right to left. 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 00:11:44.550 --> 00:11:45.240 on the left. 00:11:45.240 --> 00:11:48.400 The assignment copies the value from the right to the left. 00:11:48.400 --> 00:11:49.780 Well, how else might I do this? 00:11:49.780 --> 00:11:55.110 Well, I will say that most programmers, computer scientists more generally, 00:11:55.110 --> 00:11:57.180 tend to start counting from 0. 00:11:57.180 --> 00:11:59.640 It's a convention and it actually has upsides even 00:11:59.640 --> 00:12:02.440 in Python and other languages where generally speaking, 00:12:02.440 --> 00:12:04.600 it's a good thing to start counting from 0 00:12:04.600 --> 00:12:07.620 instead of counting like we might in the real world from 1. 00:12:07.620 --> 00:12:10.170 Let's go ahead and adopt that convention now. 00:12:10.170 --> 00:12:14.400 Let me set i equal to 0, and I need to make a change now. 00:12:14.400 --> 00:12:19.560 Notice, if I don't change my logic, this program just became buggy. 00:12:19.560 --> 00:12:20.730 The cat has a bug. 00:12:20.730 --> 00:12:23.940 It's now meowing four times if I run it as is. 00:12:23.940 --> 00:12:27.660 But the easiest fix here would be to change my inequality 00:12:27.660 --> 00:12:31.810 to be this, less than instead of less than or equal to. 00:12:31.810 --> 00:12:36.480 Now I'm starting at 0, but I'm going up to but not through 3. 00:12:36.480 --> 00:12:40.020 And even though this might, of all the things we've seen thus far, 00:12:40.020 --> 00:12:44.400 seem maybe the least familiar, most of us might start at 1, 2, then 3, 00:12:44.400 --> 00:12:47.220 it's a good habit to get into now, start at 0, 00:12:47.220 --> 00:12:52.110 and go up to but not through the value that you care about ultimately, 00:12:52.110 --> 00:12:53.510 3 in this case here. 00:12:53.510 --> 00:12:55.260 Well, let me tighten things up a bit here. 00:12:55.260 --> 00:12:57.630 Not only will this now fix my counting problem, 00:12:57.630 --> 00:13:00.330 it now meows 3 times as expected, there's 00:13:00.330 --> 00:13:03.240 a more succinct way to express i equals i 00:13:03.240 --> 00:13:06.690 plus 1, and this, is because it's such a popular thing to do in code. 00:13:06.690 --> 00:13:11.830 You can instead just say i plus equals 1, and that's it. 00:13:11.830 --> 00:13:14.250 You don't need to put everything on the right-hand side. 00:13:14.250 --> 00:13:19.320 This is a special syntax that says the exact same thing, increment i, 00:13:19.320 --> 00:13:21.742 but it does it with a few fewer keystrokes. 00:13:21.742 --> 00:13:24.700 It's just a little more pleasant to type, it's a little faster to read, 00:13:24.700 --> 00:13:25.830 it's just a convention. 00:13:25.830 --> 00:13:29.745 Those of you who have programmed in C, C++, Python-- 00:13:29.745 --> 00:13:30.660 no, not Python. 00:13:30.660 --> 00:13:36.990 C, C++, Java, JavaScript might have seen plus-plus before or minus-minus. 00:13:36.990 --> 00:13:40.080 Sorry, Python doesn't have it, so you cannot use that. 00:13:40.080 --> 00:13:44.040 This is as succinct as your line of code might get. 00:13:44.040 --> 00:13:44.870 All right. 00:13:44.870 --> 00:13:46.620 Let me pause here to see, then, if there's 00:13:46.620 --> 00:13:53.400 any questions about these implementations of while loops. 00:13:53.400 --> 00:13:55.620 AUDIENCE: Can we use stuff like for loops 00:13:55.620 --> 00:14:02.760 which have a certain i-value initialized to it at the start 00:14:02.760 --> 00:14:09.300 and it runs from the particular condition you put into the thing 00:14:09.300 --> 00:14:12.090 and increment it as you go along? 00:14:12.090 --> 00:14:15.700 DAVID MALAN: Short answer, no, you cannot do what you're describing, 00:14:15.700 --> 00:14:18.790 but there is another type of for loop that we will soon see. 00:14:18.790 --> 00:14:20.520 But let's come to that in just a moment. 00:14:20.520 --> 00:14:26.080 Other questions on loops using while here? 00:14:26.080 --> 00:14:28.443 AUDIENCE: So I had a question about that flowchart. 00:14:28.443 --> 00:14:29.110 DAVID MALAN: OK. 00:14:29.110 --> 00:14:30.490 AUDIENCE: There were-- yeah. 00:14:30.490 --> 00:14:36.510 There were certain symbols for the certain kind of the statements were-- 00:14:36.510 --> 00:14:42.283 are they certainly used for that kind of statement that they-- 00:14:42.283 --> 00:14:43.200 DAVID MALAN: They are. 00:14:43.200 --> 00:14:44.790 So I deliberate-- 00:14:44.790 --> 00:14:47.340 I deliberately use certain types of symbols, certain shapes 00:14:47.340 --> 00:14:51.570 here whereby an oval is conventional for start and stop. 00:14:51.570 --> 00:14:56.820 I used rectangles for any statement of code, like an assignment or a printing 00:14:56.820 --> 00:14:57.630 and so forth. 00:14:57.630 --> 00:15:02.040 And I used diamonds to represent questions that you might ask, 00:15:02.040 --> 00:15:03.988 conditions as we've seen. 00:15:03.988 --> 00:15:06.030 If you're doing this for yourself, if you're just 00:15:06.030 --> 00:15:07.950 trying to make sense of your code and writing it down, 00:15:07.950 --> 00:15:10.158 you certainly don't need to use these formal symbols, 00:15:10.158 --> 00:15:13.367 but I tried to be consistent with some best practices. 00:15:13.367 --> 00:15:15.450 And in fact, let me come back to the same picture, 00:15:15.450 --> 00:15:17.533 because this was the first version of our picture, 00:15:17.533 --> 00:15:19.830 but we've since modified our code a couple of times. 00:15:19.830 --> 00:15:22.455 This, recall, was the version where the question we were asking 00:15:22.455 --> 00:15:26.340 was i not equal to 0, let me go ahead and just change this code now 00:15:26.340 --> 00:15:29.250 to represent the next version we did, which, recall, 00:15:29.250 --> 00:15:31.950 changed our logic to start counting from 1, 00:15:31.950 --> 00:15:36.060 it changed our question to check as i less than or equal to 3, 00:15:36.060 --> 00:15:39.570 but then everything else was the same except for the counting, which 00:15:39.570 --> 00:15:41.580 is now plus instead of minus. 00:15:41.580 --> 00:15:47.040 And then we refined it a little bit further by counting now from 0 up to 00:15:47.040 --> 00:15:48.570 but not through 3. 00:15:48.570 --> 00:15:52.170 And we tightened up this code here by just incrementing 1 00:15:52.170 --> 00:15:54.220 by using the slightly more succinct syntax. 00:15:54.220 --> 00:15:57.120 So at this point, these flowcharts might become less and less useful 00:15:57.120 --> 00:16:00.690 for us, because once you've wrapped your mind around the concept 00:16:00.690 --> 00:16:03.750 and hopefully the picture helps bring that concept to life, 00:16:03.750 --> 00:16:06.600 it certainly fine to focus entirely on the code 00:16:06.600 --> 00:16:09.240 and only think about or even draw something like this 00:16:09.240 --> 00:16:12.120 if you need to wrap your mind around something more complicated 00:16:12.120 --> 00:16:13.200 than you're used to. 00:16:13.200 --> 00:16:15.240 Well, let me go ahead, if I may, and propose 00:16:15.240 --> 00:16:20.490 that we transition to another approach of types of loops using another 00:16:20.490 --> 00:16:22.740 keyword here, namely a for loop. 00:16:22.740 --> 00:16:25.050 And this is a word that does exist in other languages, 00:16:25.050 --> 00:16:28.290 but doesn't necessarily have as many features as other languages might 00:16:28.290 --> 00:16:29.260 use it for. 00:16:29.260 --> 00:16:33.300 But there is a different type of loop-- not a while loop, but a for loop. 00:16:33.300 --> 00:16:37.620 And a for loop is going to allow us to express ourselves a little differently, 00:16:37.620 --> 00:16:40.020 but to do so, I propose that the easiest way 00:16:40.020 --> 00:16:43.890 is if we introduce one other idea in Python, which is that of a list. 00:16:43.890 --> 00:16:48.120 And here, too, no pun intended, we're adding to the list of data types 00:16:48.120 --> 00:16:49.290 that Python supports. 00:16:49.290 --> 00:16:51.480 We've seen strs or strings. 00:16:51.480 --> 00:16:53.050 Ints or integers. 00:16:53.050 --> 00:16:54.780 Floats or floating point values. 00:16:54.780 --> 00:16:56.670 Bools or Boolean expressions. 00:16:56.670 --> 00:17:00.480 Python also has lists, which is another type of data, 00:17:00.480 --> 00:17:02.730 but wonderfully, this one is probably pretty familiar. 00:17:02.730 --> 00:17:06.240 A list of things in the real world is a list of things in Python. 00:17:06.240 --> 00:17:11.490 It's a way of containing multiple values all in the same place, all 00:17:11.490 --> 00:17:12.940 in the same variable. 00:17:12.940 --> 00:17:14.319 So what do I mean by this? 00:17:14.319 --> 00:17:18.480 Well let me propose that we go back to our VS Code here, 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, 00:17:22.480 --> 00:17:24.690 but let me use this new keyword for. 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. 00:17:30.363 --> 00:17:31.530 So what does this look like? 00:17:31.530 --> 00:17:32.940 It might look like this-- 00:17:32.940 --> 00:17:39.030 for i and the following list of items, 0, 1, 2. 00:17:39.030 --> 00:17:41.640 This is my starting point, and on each iteration 00:17:41.640 --> 00:17:45.450 of this loop-- that is, on each execution of this loop again and again, 00:17:45.450 --> 00:17:47.550 I want to print out meow. 00:17:47.550 --> 00:17:51.360 Now I'll admit, I kind of like the look of this code already 00:17:51.360 --> 00:17:53.580 even though there's some new syntax here, 00:17:53.580 --> 00:17:55.770 because it's just shorter than the while loop. 00:17:55.770 --> 00:17:58.480 The while loop had multiple lines a moment ago 00:17:58.480 --> 00:18:01.320 and it was entirely up to me to decide what i is. 00:18:01.320 --> 00:18:04.530 I have to check a condition, I have to increment or decrement i. 00:18:04.530 --> 00:18:07.230 Like I was doing a lot of work, relatively speaking, 00:18:07.230 --> 00:18:10.710 to make that thing turn, to make that loop going to go. 00:18:10.710 --> 00:18:12.720 It was very mechanical in a sense. 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 00:18:18.030 --> 00:18:21.120 are changing and these questions are being asked. 00:18:21.120 --> 00:18:24.450 A for loop simplifies all of that, and it just 00:18:24.450 --> 00:18:27.480 says, if you want a variable like i, a number, 00:18:27.480 --> 00:18:31.770 and you know in advance how many times want this loop to execute-- three 00:18:31.770 --> 00:18:34.380 times, we'll just kind of specify what it 00:18:34.380 --> 00:18:37.560 is you want i to take on as values explicitly. 00:18:37.560 --> 00:18:41.940 In this loop, i will be automatically initialized by Python to be 0, 00:18:41.940 --> 00:18:43.530 then meow will be printed. 00:18:43.530 --> 00:18:48.870 Then Python would automatically update i to equal 1, then meow will be printed. 00:18:48.870 --> 00:18:53.520 Then Python will automatically update i to be 2 and meow will be printed. 00:18:53.520 --> 00:18:57.270 And because that's it for the values in that list, Python will stop 00:18:57.270 --> 00:19:00.090 and it will only meow a total of three times. 00:19:00.090 --> 00:19:01.170 What is the list? 00:19:01.170 --> 00:19:05.130 The list in this program is exactly that, 0, comma, 1, comma, 2, 00:19:05.130 --> 00:19:07.200 and notice the square brackets. 00:19:07.200 --> 00:19:11.350 Those aren't parentheses, those are square brackets that represent a list. 00:19:11.350 --> 00:19:15.540 That's how visually as the programmer-- that's how Python knows as the language 00:19:15.540 --> 00:19:18.460 that you intend for that to be a list. 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. 00:19:23.490 --> 00:19:24.660 But it's only two lines. 00:19:24.660 --> 00:19:28.330 It's pretty readable once you have familiarity with that construct, 00:19:28.330 --> 00:19:33.970 but to my constant point about correctness not necessarily 00:19:33.970 --> 00:19:38.800 being the same as design, in what sense is this program perhaps 00:19:38.800 --> 00:19:40.150 poorly designed? 00:19:40.150 --> 00:19:41.140 It seems to work. 00:19:41.140 --> 00:19:45.790 It meows three times, but why might this not 00:19:45.790 --> 00:19:48.130 be the best way to solve this problem? 00:19:48.130 --> 00:19:51.190 Even if you've never programmed before, again, 00:19:51.190 --> 00:19:54.310 think about corner cases, things that may or may not happen. 00:19:54.310 --> 00:19:59.168 Think about extreme cases that really test the quality of this code. 00:19:59.168 --> 00:19:59.710 AUDIENCE: OK. 00:19:59.710 --> 00:20:06.880 I think that because we are saying 0, 1, 2 3 times. 00:20:06.880 --> 00:20:11.030 And then if you want to take a million, you say 1, 2, 3. 00:20:11.030 --> 00:20:12.967 DAVID MALAN: Yeah, exactly. 00:20:12.967 --> 00:20:15.550 And that's what I mean about thinking about the extreme cases. 00:20:15.550 --> 00:20:18.430 If you're trying to decide for yourself if your own code is good 00:20:18.430 --> 00:20:22.120 or someone else's code is good, it might look so at first glance, 00:20:22.120 --> 00:20:23.530 but think about the extreme. 00:20:23.530 --> 00:20:26.410 Well, what if it's not three things, it's a million things? 00:20:26.410 --> 00:20:31.180 I mean, are you really going to write out 0 through a million or 0 00:20:31.180 --> 00:20:33.160 through 9-- 00:20:33.160 --> 00:20:38.090 999,999? 00:20:38.090 --> 00:20:40.840 Like no, you're not going to write that many numbers on the screen 00:20:40.840 --> 00:20:42.500 there's got to be a better way. 00:20:42.500 --> 00:20:45.100 So let's do the better way from the get-go 00:20:45.100 --> 00:20:47.980 rather than set the stage for doing something poorly. 00:20:47.980 --> 00:20:52.090 And the one way we can solve this problem to improve the design 00:20:52.090 --> 00:20:56.950 is don't just manually specify the list of values, use a function, 00:20:56.950 --> 00:20:59.140 someone else's function that comes with Python 00:20:59.140 --> 00:21:00.850 that gives you the list you want. 00:21:00.850 --> 00:21:02.680 And the easiest way to do that in Python is 00:21:02.680 --> 00:21:07.480 to use a function called range that returns to a range of values. 00:21:07.480 --> 00:21:09.940 It expects as input at least one argument, 00:21:09.940 --> 00:21:14.170 and that number is going to be the number of values you want back. 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, 00:21:18.620 --> 00:21:22.910 but they will go up two but not through the number you specify. 00:21:22.910 --> 00:21:26.200 So by specifying range 3, you're essentially 00:21:26.200 --> 00:21:29.350 being handed back 1, 2, 3 values. 00:21:29.350 --> 00:21:33.730 And by default, those values are 0, 1, and 2, and that's it. 00:21:33.730 --> 00:21:37.240 But what's brilliant about this is that now, to Hope's point, if I do 00:21:37.240 --> 00:21:38.950 want to meow a million times-- 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. 00:21:44.320 --> 00:21:48.910 I don't have to literally type 0, comma, 1, comma, 2, comma, 3, comma, 00:21:48.910 --> 00:21:53.620 4, all the way up to 999,999, I just do this. 00:21:53.620 --> 00:21:57.140 So that's got to be a better way long-term. 00:21:57.140 --> 00:21:59.080 So that's indeed one improvement we can indeed 00:21:59.080 --> 00:22:03.050 make here still using a for loop, but now using this range function. 00:22:03.050 --> 00:22:05.470 And just to show you something else that's Pythonic-- 00:22:05.470 --> 00:22:07.690 this is not strictly necessary, but it's commonly 00:22:07.690 --> 00:22:11.560 done, there's a minor improvement we can make here, 00:22:11.560 --> 00:22:14.180 even if we're just meowing three times. 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. 00:22:20.710 --> 00:22:24.700 And it's kind of necessary logically, because Python, presumably, 00:22:24.700 --> 00:22:26.620 has to use something for counting. 00:22:26.620 --> 00:22:28.960 It has to know what it's iterating over. 00:22:28.960 --> 00:22:30.970 But there's this convention in Python where 00:22:30.970 --> 00:22:35.320 if you need a variable, just because the programming feature requires 00:22:35.320 --> 00:22:38.890 it to do some kind of counting or automatic updating, but you, the human, 00:22:38.890 --> 00:22:42.550 don't care about its value, a Pythonic improvement here 00:22:42.550 --> 00:22:45.520 would be to name that variable a single underscore. 00:22:45.520 --> 00:22:48.280 Just because it's not required, it doesn't 00:22:48.280 --> 00:22:50.410 change the correctness of the program, but it 00:22:50.410 --> 00:22:54.190 signals to yourself later, it signals to colleagues or teachers that 00:22:54.190 --> 00:22:57.207 are looking at your code, too, that yes, it's a variable, 00:22:57.207 --> 00:23:00.040 but you don't care about its name because you're not using it later, 00:23:00.040 --> 00:23:04.840 it's just necessary in order to use this feature, this loop in this case here. 00:23:04.840 --> 00:23:09.190 So just a minor improvement or change there. 00:23:09.190 --> 00:23:13.510 But to really gets you intrigued by what's possible in Python, 00:23:13.510 --> 00:23:15.140 let's take this one step further. 00:23:15.140 --> 00:23:19.780 So if we really want to be Pythonic, this one, if you've programmed before, 00:23:19.780 --> 00:23:22.310 is kind of going to blow your mind, so to speak, 00:23:22.310 --> 00:23:27.820 whereby if I want the cat to meow three times, what if I actually do this? 00:23:27.820 --> 00:23:34.350 print, open parenthesis, quote-unquote, meow times 3. 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. 00:23:37.620 --> 00:23:40.620 So you can literally just print what you want, 00:23:40.620 --> 00:23:44.070 multiply it by the number of times that you want it, 00:23:44.070 --> 00:23:47.760 and you will get back exactly that result. 00:23:47.760 --> 00:23:50.763 Now I've kind of made a mistake here. 00:23:50.763 --> 00:23:51.930 So let's see what this does. 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, 00:23:56.730 --> 00:23:57.240 to me. 00:23:57.240 --> 00:24:00.300 Let me run Python of cat.py, Enter. 00:24:00.300 --> 00:24:02.820 OK, it's a really like hungry cat or something. 00:24:02.820 --> 00:24:04.350 It's meowing really fast. 00:24:04.350 --> 00:24:06.830 But I can fix this, I bet. 00:24:06.830 --> 00:24:10.010 Let's think about now some of the basic building blocks we've discussed. 00:24:10.010 --> 00:24:13.160 The problem is clearly that literally meow, meow, 00:24:13.160 --> 00:24:16.460 meow is being repeated three times, but it's not as pretty as I want it. 00:24:16.460 --> 00:24:19.910 I want it to be meow, meow, meow on separate lines. 00:24:19.910 --> 00:24:22.850 What might be a possible solution here while still 00:24:22.850 --> 00:24:26.780 using this multiplication operator? 00:24:26.780 --> 00:24:27.560 And think back. 00:24:27.560 --> 00:24:30.170 We've used plus to concatenate strings. 00:24:30.170 --> 00:24:33.980 You can apparently use multiplication to concatenate strings, but more than once 00:24:33.980 --> 00:24:35.180 again and again and again. 00:24:35.180 --> 00:24:37.580 How could I clean this up without reverting 00:24:37.580 --> 00:24:42.240 to my for loop or my while loop and still use multiplication in this way? 00:24:42.240 --> 00:24:45.975 AUDIENCE: We can use the escape sequence which would be backslash n. 00:24:45.975 --> 00:24:46.850 DAVID MALAN: Amazing. 00:24:46.850 --> 00:24:47.350 Yes. 00:24:47.350 --> 00:24:50.750 Think back to backslash n, which is the way you as the programmer 00:24:50.750 --> 00:24:52.970 can express a new line in code. 00:24:52.970 --> 00:24:57.560 And I think, if I take your advice, I put a backslash in there inside 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, 00:25:02.390 --> 00:25:03.470 let's see how this looks. 00:25:03.470 --> 00:25:06.650 Let me clear my screen and run Python of cat.py. 00:25:06.650 --> 00:25:08.270 OK, so close. 00:25:08.270 --> 00:25:09.030 I like this. 00:25:09.030 --> 00:25:10.490 Let me call on someone else. 00:25:10.490 --> 00:25:13.670 The only thing I don't like-- and I know I'm being really nitpicky now-- 00:25:13.670 --> 00:25:15.840 is that it's meow, meow, meow on separate lines, 00:25:15.840 --> 00:25:20.300 but there's this extra blank line, which I'm just not loving aesthetically. 00:25:20.300 --> 00:25:25.430 AUDIENCE: I think we can make n equal to column-- 00:25:25.430 --> 00:25:27.410 column, not-- like a slash n. 00:25:27.410 --> 00:25:28.160 DAVID MALAN: Yeah. 00:25:28.160 --> 00:25:31.010 So here, too, like all of these things we've seen in past weeks 00:25:31.010 --> 00:25:32.630 are kind of coming together. 00:25:32.630 --> 00:25:37.010 Recall that the print function lets you control what the line ending is. 00:25:37.010 --> 00:25:39.570 By default, it's backslash n itself. 00:25:39.570 --> 00:25:41.540 Which is why at the very end of this print, 00:25:41.540 --> 00:25:44.300 the cursor is being moved again to the next line. 00:25:44.300 --> 00:25:46.260 Well, we need to just override that. 00:25:46.260 --> 00:25:50.420 So let me go into my code here and let me change this to comma n 00:25:50.420 --> 00:25:54.890 equals quote-unquote so that it's no longer the default backslash n, 00:25:54.890 --> 00:25:59.150 it's instead now going to be nothing whatsoever. 00:25:59.150 --> 00:26:03.890 That should eliminate, then, hopefully that additional blank line. 00:26:03.890 --> 00:26:07.220 So let me run this one last time here, Python of cat.py, Enter, 00:26:07.220 --> 00:26:08.640 and there we have it. 00:26:08.640 --> 00:26:12.200 So now, at least as programming goes, it's 00:26:12.200 --> 00:26:15.530 kind of cool that I can distill this into a short line 00:26:15.530 --> 00:26:17.120 and express myself all at once. 00:26:17.120 --> 00:26:19.520 Now to be fair, it's a little less readable. 00:26:19.520 --> 00:26:21.950 Like now I've got backslash n, I've got times 3, 00:26:21.950 --> 00:26:23.390 I've got n equals quote-unquote. 00:26:23.390 --> 00:26:25.400 So you don't have to do things this way. 00:26:25.400 --> 00:26:28.440 My previous approach with a for loop, totally fine. 00:26:28.440 --> 00:26:31.940 My previous approach with a while loop, totally fine, and in some sense, 00:26:31.940 --> 00:26:33.740 perfectly well-designed. 00:26:33.740 --> 00:26:36.600 But this is just yet another way to do it, 00:26:36.600 --> 00:26:40.250 but it's not a good thing if you or your teacher, your colleague, your friend 00:26:40.250 --> 00:26:42.410 are going to struggle to read your own code. 00:26:42.410 --> 00:26:47.870 But this is a feature of Python that some languages do not, in fact, have. 00:26:47.870 --> 00:26:51.110 All right, well let me propose that things get more interesting still 00:26:51.110 --> 00:26:53.690 if we're not just meowing three times only, 00:26:53.690 --> 00:26:56.180 but we're meowing some variable number of times. 00:26:56.180 --> 00:26:58.940 Let's ask the user how many times this cat should meow. 00:26:58.940 --> 00:27:03.540 So let me clear the screen here, and let me figure out, well, 00:27:03.540 --> 00:27:05.760 how do I get a number from the user? 00:27:05.760 --> 00:27:08.670 The catch here is that if I want the user to give me a number, 00:27:08.670 --> 00:27:12.290 I'm not doing math, per se, I'm meowing, and therefore, the user 00:27:12.290 --> 00:27:14.630 has to give me a positive value. 00:27:14.630 --> 00:27:17.100 The user has to give me a positive value. 00:27:17.100 --> 00:27:18.860 So how can I insist on this? 00:27:18.860 --> 00:27:25.800 Well, if I just do this, n equals int of input, what's n, question mark? 00:27:25.800 --> 00:27:28.040 Well, I want to check like-- 00:27:28.040 --> 00:27:32.150 I could say if n is less than 0-- 00:27:32.150 --> 00:27:34.430 like if it's negative, well I could do this. 00:27:34.430 --> 00:27:35.870 Well, then ask again. 00:27:35.870 --> 00:27:40.370 Int, input, what's n, question mark? 00:27:40.370 --> 00:27:43.312 OK, well what if the user still doesn't give me a positive number? 00:27:43.312 --> 00:27:45.770 What if being really difficult they're not paying attention 00:27:45.770 --> 00:27:47.395 and they typed in two negative numbers? 00:27:47.395 --> 00:27:53.000 Well, if n is less than 0, well, let's do it again. n equals-- 00:27:53.000 --> 00:27:54.170 this does not end well. 00:27:54.170 --> 00:27:58.070 You can't infinitely many times keep checking, is it negative, 00:27:58.070 --> 00:27:59.630 is it negative, or is it negative? 00:27:59.630 --> 00:28:01.700 The program would never be done written. 00:28:01.700 --> 00:28:05.010 So we can do this I think better maybe with a loop. 00:28:05.010 --> 00:28:06.200 So let me propose this. 00:28:06.200 --> 00:28:09.020 A very common paradigm in Python, when you 00:28:09.020 --> 00:28:14.000 want to get user input that matches a certain expectation you have, 00:28:14.000 --> 00:28:17.570 that it's all positive, that it's all negative, or just something like that, 00:28:17.570 --> 00:28:20.840 you just immediately say while true. 00:28:20.840 --> 00:28:24.380 You deliberately, and a little dangerously but a very conventionally, 00:28:24.380 --> 00:28:25.962 induce an infinite loop. 00:28:25.962 --> 00:28:27.170 Now what is an infinite loop? 00:28:27.170 --> 00:28:28.550 It's just one that goes forever. 00:28:28.550 --> 00:28:31.430 And we've seen how that can happen accidentally mathematically. 00:28:31.430 --> 00:28:34.700 It's absolutely going to happen when you say while true. 00:28:34.700 --> 00:28:35.240 Why? 00:28:35.240 --> 00:28:39.180 Well, the answer to the true question is always true. 00:28:39.180 --> 00:28:41.570 So this is a way of deliberately inducing a loop that 00:28:41.570 --> 00:28:43.470 by default is going to go forever. 00:28:43.470 --> 00:28:46.940 So we're going to need a way of breaking out of this loop when 00:28:46.940 --> 00:28:48.350 we have the number we want. 00:28:48.350 --> 00:28:50.600 The convention, though inside of this otherwise 00:28:50.600 --> 00:28:52.970 an infinite loop is to ask the question you care about, 00:28:52.970 --> 00:28:55.760 like give me an int by prompting the user for input. 00:28:55.760 --> 00:28:57.800 Like what's n, question mark? 00:28:57.800 --> 00:28:59.330 And then just ask your question. 00:28:59.330 --> 00:29:04.580 So if n is less than 0, then I think we want Python to just continue 00:29:04.580 --> 00:29:05.910 to prompt the user again. 00:29:05.910 --> 00:29:09.760 That is, we want the code to stay in the loop, recall the input function, 00:29:09.760 --> 00:29:11.760 and hope that the user gives us a better answer. 00:29:11.760 --> 00:29:14.730 If this time around it's less than 0, so let's just literally 00:29:14.730 --> 00:29:16.980 use Python's keyword continue, which says 00:29:16.980 --> 00:29:20.100 just that-- continue to stay within this loop. 00:29:20.100 --> 00:29:24.000 Else, if it's not less than 0, let's go ahead and just break out 00:29:24.000 --> 00:29:27.120 of the loop altogether using another keyword in Python, break. 00:29:27.120 --> 00:29:31.140 Break will break you out of the most recently begun loop in this case 00:29:31.140 --> 00:29:34.080 if it's not the case that n is less than 0. 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 00:29:38.310 --> 00:29:41.340 from the user, but I think we can tighten it up further so as to not 00:29:41.340 --> 00:29:43.500 bother having an if, and, and else. 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? 00:29:49.227 --> 00:29:51.060 In fact, it's not that interesting a program 00:29:51.060 --> 00:29:52.830 if we even allow the user to type in 0. 00:29:52.830 --> 00:29:56.430 So let's wait until they give us an integer that is greater than 0 00:29:56.430 --> 00:29:59.040 and then break out of this loop. 00:29:59.040 --> 00:30:00.960 And what can I now do down here? 00:30:00.960 --> 00:30:07.260 For i in range of whatever that value n is, print meow. 00:30:07.260 --> 00:30:10.340 And honestly, I don't need i here, so let me come back to that principle 00:30:10.340 --> 00:30:10.840 before. 00:30:10.840 --> 00:30:12.590 And let me just change it to an underscore 00:30:12.590 --> 00:30:14.110 just to be Pythonic, if you will. 00:30:14.110 --> 00:30:15.360 So what's going on? 00:30:15.360 --> 00:30:20.130 Lines 1 through 4 deliberately implement an infinite loop 00:30:20.130 --> 00:30:23.280 that otherwise by default is going to go forever. 00:30:23.280 --> 00:30:26.370 But I'm asking a question, inside of that loop, 00:30:26.370 --> 00:30:30.450 after getting an int from the user on line 2, I'm then checking, 00:30:30.450 --> 00:30:32.310 is it greater than 0? 00:30:32.310 --> 00:30:33.570 Or is it 0? 00:30:33.570 --> 00:30:34.220 Is it negative? 00:30:34.220 --> 00:30:35.970 None of which makes sense for meowing cat. 00:30:35.970 --> 00:30:38.380 Like I want the cat to meow at least one time. 00:30:38.380 --> 00:30:41.220 So if it is greater than 0, break. 00:30:41.220 --> 00:30:45.030 And this break statement, even though it's indented, indented twice, 00:30:45.030 --> 00:30:50.140 has the effect of breaking out of the most recently begun while loop. 00:30:50.140 --> 00:30:53.670 So once the user gives you a positive value, 00:30:53.670 --> 00:30:58.650 then we get to line 6, at which point we meow that many times because 00:30:58.650 --> 00:30:59.850 of line 6 and 7. 00:30:59.850 --> 00:31:03.960 So if I run this now Python of cat.py, Enter, well, what's n? 00:31:03.960 --> 00:31:06.895 Let's start with 3 where we began, meow, meow, meow. 00:31:06.895 --> 00:31:10.020 Well this time, let me go ahead and increase the size of my terminal window 00:31:10.020 --> 00:31:11.100 just temporarily. 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 00:31:16.140 --> 00:31:17.520 appears on the screen. 00:31:17.520 --> 00:31:20.640 And the takeaways here are not just that we can meow 10 times 00:31:20.640 --> 00:31:22.890 or do something again and again, but this 00:31:22.890 --> 00:31:26.880 is a very common paradigm in Python when you want to do something again 00:31:26.880 --> 00:31:31.320 and again and again, but only until the user actually gives you 00:31:31.320 --> 00:31:34.230 a value that you care about here. 00:31:34.230 --> 00:31:36.540 And let me propose actually now that we practice 00:31:36.540 --> 00:31:41.830 a little more what we've been preaching, especially when it comes to, say-- 00:31:41.830 --> 00:31:45.075 especially when it comes to say writing your own functions. 00:31:45.075 --> 00:31:46.950 Now that I'm doing all this meowing, it might 00:31:46.950 --> 00:31:50.970 be nice to actually have a meow function that the inventors of Python 00:31:50.970 --> 00:31:52.680 didn't envision, so let me do this. 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. 00:31:56.050 --> 00:31:59.950 Let me go ahead and say define a main function, as I've done before, 00:31:59.950 --> 00:32:02.400 and let me just blindly call meow 3. 00:32:02.400 --> 00:32:05.910 Meow doesn't exist yet, but when it does, that'll be great. 00:32:05.910 --> 00:32:08.640 So let me go ahead now and define meow. 00:32:08.640 --> 00:32:11.850 So am I meow function should take as input 00:32:11.850 --> 00:32:16.350 a parameter called n or anything I want, and this part's pretty easy now. 00:32:16.350 --> 00:32:17.880 How do you meow n times? 00:32:17.880 --> 00:32:22.470 Well, for underscore n, the range of n, go ahead and just print meow. 00:32:22.470 --> 00:32:24.780 So same code as before, nothing new here, 00:32:24.780 --> 00:32:28.470 I'm just putting that logic inside of a meow function 00:32:28.470 --> 00:32:30.810 that's going to have this side effect of printing meow. 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. 00:32:34.620 --> 00:32:39.420 And if I now run this code, Python of cat.py, meow, meow, meow. 00:32:39.420 --> 00:32:42.960 It's always going to do three because I've hardcoded to 3. 00:32:42.960 --> 00:32:44.730 Well, let's make one improvement here. 00:32:44.730 --> 00:32:48.720 Let me go ahead now and maybe do this. 00:32:48.720 --> 00:32:50.350 Let me ask the user for a number. 00:32:50.350 --> 00:32:54.700 So let's say something like this, number equals get number. 00:32:54.700 --> 00:32:55.200 All right. 00:32:55.200 --> 00:32:57.210 Unfortunately, there is no function in Python 00:32:57.210 --> 00:32:59.940 called get number that gets a positive number from the user, 00:32:59.940 --> 00:33:01.080 but I can invent that. 00:33:01.080 --> 00:33:05.070 So define get number, open paren, close paren. 00:33:05.070 --> 00:33:07.260 And then inside of this function, let me do this. 00:33:07.260 --> 00:33:11.160 While true, go ahead and get a number from the user, 00:33:11.160 --> 00:33:14.730 converting it to an int asking them, what's n, question mark? 00:33:14.730 --> 00:33:19.260 And then if n is what I want, it's a greater than 0 value, 00:33:19.260 --> 00:33:24.710 a positive number, I don't want to break this time necessarily, 00:33:24.710 --> 00:33:26.000 although I could. 00:33:26.000 --> 00:33:30.750 I instead want to return the value so I can actually do this instead. 00:33:30.750 --> 00:33:32.600 And this, too, is a feature of Python. 00:33:32.600 --> 00:33:35.690 This ability not to just break out of a block of code, 00:33:35.690 --> 00:33:38.750 but also to return a value in code. 00:33:38.750 --> 00:33:42.590 To actually return a value gives you the ability, ultimately, 00:33:42.590 --> 00:33:47.030 to return explicitly a value so that your function has not just a side 00:33:47.030 --> 00:33:51.650 effect, necessarily, but it actually hands back, just like input does, 00:33:51.650 --> 00:33:56.220 just like int does, just like float does, an actual value to the user. 00:33:56.220 --> 00:33:58.790 Now to be clear, I don't have to return n here. 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 00:34:02.330 --> 00:34:06.860 like this, but then after the loop, I still have to return. 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, 00:34:10.969 --> 00:34:13.730 but you need to hand back a value from a function, 00:34:13.730 --> 00:34:15.980 you still have to use the return keyword now 00:34:15.980 --> 00:34:20.389 explicitly either in the loop as I did or now outside of the loop 00:34:20.389 --> 00:34:24.110 but still inside of the function. 00:34:24.110 --> 00:34:26.420 The last thing I'm going to do here now is change 00:34:26.420 --> 00:34:28.969 that 3, which we hardcoded earlier, to actually 00:34:28.969 --> 00:34:31.590 be the value of the variable we've gotten from the user 00:34:31.590 --> 00:34:36.380 so that now down here, if I run Python of cat.py, Enter, what's n? 00:34:36.380 --> 00:34:40.219 I can type in 3, I get my three meows, or if I only want one, 00:34:40.219 --> 00:34:43.020 I now get one meow instead. 00:34:43.020 --> 00:34:43.520 All right. 00:34:43.520 --> 00:34:48.230 So if we now have this ability to do things again and again in these loops, 00:34:48.230 --> 00:34:51.800 let's see if we can't solve some other problems via which 00:34:51.800 --> 00:34:55.894 to express ourselves cyclically, but get back some interesting answers as well. 00:34:55.894 --> 00:34:58.898 And let me propose, for instance, that we look 00:34:58.898 --> 00:35:00.440 a little more closely at these lists. 00:35:00.440 --> 00:35:03.107 It turns out that in Python, and really, in programs in general, 00:35:03.107 --> 00:35:05.600 it's useful to have a list of values, because we're 00:35:05.600 --> 00:35:10.160 going to be able to work with more and more data, larger and larger data sets. 00:35:10.160 --> 00:35:12.530 So let me propose that we come back to VS Code here 00:35:12.530 --> 00:35:15.620 and let's do something that's perhaps a little familiar to some folks, 00:35:15.620 --> 00:35:17.030 the world of Hogwarts. 00:35:17.030 --> 00:35:19.850 And let me go ahead and code up a file called Hogwarts, 00:35:19.850 --> 00:35:23.840 and let's see if we can't have a list of students at Hogwarts here. 00:35:23.840 --> 00:35:26.270 So I have a new tab called hogwarts.py. 00:35:26.270 --> 00:35:30.710 and let me go ahead and propose that I just define in this program 00:35:30.710 --> 00:35:32.780 a list of students whose names I know in advance. 00:35:32.780 --> 00:35:34.572 So I'm not going to get user input for now. 00:35:34.572 --> 00:35:37.250 I'm just going to know from the get-go that the three 00:35:37.250 --> 00:35:39.110 students I want to consider are these. 00:35:39.110 --> 00:35:41.030 Our variable is going to be called students. 00:35:41.030 --> 00:35:44.540 It's going to equal, as I've done in the past, a square bracket, which 00:35:44.540 --> 00:35:46.100 means, hey, here comes a list. 00:35:46.100 --> 00:35:49.520 And those values are going to be Hermione in quotes, because it's 00:35:49.520 --> 00:35:53.980 a string; Harry in quotes, because it's a string; and then Ron in quotes, 00:35:53.980 --> 00:35:55.230 because it's a string as well. 00:35:55.230 --> 00:35:57.800 So this is a list of length 3. 00:35:57.800 --> 00:36:00.500 It's similar in spirit to my list of length 3 earlier, 00:36:00.500 --> 00:36:02.960 but that had 3 ints, 0, 1, 2. 00:36:02.960 --> 00:36:06.020 Now I have a list of three strings instead. 00:36:06.020 --> 00:36:08.940 And this isn't very useful at the moment, 00:36:08.940 --> 00:36:11.600 but let me just do something as a check for myself. 00:36:11.600 --> 00:36:14.510 Let me print out each of these students. 00:36:14.510 --> 00:36:19.760 Well wait a minute, how do I print the contents of a list? 00:36:19.760 --> 00:36:22.610 Well, in the past, when we've printed a variable, 00:36:22.610 --> 00:36:24.900 we've just printed out the name of the variable. 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. 00:36:28.970 --> 00:36:33.350 Maybe I want to print out Hermione first, then Harry, then Ron. 00:36:33.350 --> 00:36:36.050 So I need a way to express more precisely which 00:36:36.050 --> 00:36:37.790 value do I want from this list? 00:36:37.790 --> 00:36:42.590 And the way you do this in Python is you use square brackets in another way. 00:36:42.590 --> 00:36:45.890 If you have a variable-- in this case, called students, 00:36:45.890 --> 00:36:49.850 and you want to go inside of that variable and get a specific value-- 00:36:49.850 --> 00:36:52.940 that is to say, you want to index into the list, 00:36:52.940 --> 00:36:57.500 you use square brackets this way using numbers inside of the square brackets. 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 00:37:02.570 --> 00:37:04.280 on up instead of 1 on up. 00:37:04.280 --> 00:37:08.120 These lists in Python are, shall we say, zero-indexed. 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 00:37:13.700 --> 00:37:16.760 is that location 1, and the third is that location 2. 00:37:16.760 --> 00:37:19.940 So you're always kind of off by one mentally, but you get used to it, 00:37:19.940 --> 00:37:22.275 if you've never programmed before, over time. 00:37:22.275 --> 00:37:23.900 So let me print out all three students. 00:37:23.900 --> 00:37:27.410 So let me print out students bracket 0, then students bracket 1. 00:37:27.410 --> 00:37:30.290 Then lastly, let me print students bracket 2, 00:37:30.290 --> 00:37:32.078 and this is my third and final line. 00:37:32.078 --> 00:37:35.120 And of course, if I run this code, it probably does what you would guess. 00:37:35.120 --> 00:37:39.500 If I run Python of hogwarts.py, there's Hermione, Harry, and Ron 00:37:39.500 --> 00:37:41.450 each on their own lines there. 00:37:41.450 --> 00:37:43.443 But there's got to be a better way, especially 00:37:43.443 --> 00:37:45.860 if I don't know in advance who's going to be in this list, 00:37:45.860 --> 00:37:48.230 if next year there's some new students at Hogwarts, 00:37:48.230 --> 00:37:50.930 we can use a loop to do something automatically 00:37:50.930 --> 00:37:54.590 without having to manually type out 0 and then 1 and 2. 00:37:54.590 --> 00:37:57.110 Well, here's another feature of Python. 00:37:57.110 --> 00:38:01.310 You can use a for loop not just to count from 0 to 1 to 2, 00:38:01.310 --> 00:38:03.870 you can use Python to just iterate over anything. 00:38:03.870 --> 00:38:05.420 Not just numbers, but strings. 00:38:05.420 --> 00:38:07.100 So I could actually do this. 00:38:07.100 --> 00:38:13.460 For student in students, colon, and then indented underneath that, 00:38:13.460 --> 00:38:15.050 I can say print student. 00:38:15.050 --> 00:38:19.700 Now it doesn't matter if I have 3 students or 4 or 400, 00:38:19.700 --> 00:38:23.930 these two lines of code, this loop will print all of those students for me 00:38:23.930 --> 00:38:24.810 one at a time. 00:38:24.810 --> 00:38:28.490 So if I now run Python of hogwarts.py, there's the same list, 00:38:28.490 --> 00:38:32.420 but I don't need to know in advance how long that actual list is. 00:38:32.420 --> 00:38:35.130 Now notice, I made a conscious decision here. 00:38:35.130 --> 00:38:39.680 I didn't call this variable underscore, because this time I'm 00:38:39.680 --> 00:38:40.970 using the variable. 00:38:40.970 --> 00:38:44.210 And while I could do this, now, no, no, no, no, 00:38:44.210 --> 00:38:46.130 your code is getting way too cryptic. 00:38:46.130 --> 00:38:48.860 If you're naming the variable underscore and you're 00:38:48.860 --> 00:38:51.530 using the variable underscore, now you're helping no one. 00:38:51.530 --> 00:38:54.890 Now you're confusing the reader, yourself down the line, 00:38:54.890 --> 00:38:57.370 you should call your variables what they are. 00:38:57.370 --> 00:39:00.470 So a very appropriate name, though I'm sure you could come up with others, 00:39:00.470 --> 00:39:04.430 would be student, and here, you could say you would stay student as well. 00:39:04.430 --> 00:39:06.710 If you'd prefer to be more succinct, it's 00:39:06.710 --> 00:39:09.380 not unreasonable to do something succinct in a loop like this. 00:39:09.380 --> 00:39:13.430 For s in students, using maybe the same letter that the list 00:39:13.430 --> 00:39:15.740 itself begins with, but again, why bother? 00:39:15.740 --> 00:39:17.510 Python is meant to be more readable. 00:39:17.510 --> 00:39:22.530 If you have a list of students, iterate over them one student at a time. 00:39:22.530 --> 00:39:25.490 Let me pause here to see if there's now questions about lists 00:39:25.490 --> 00:39:28.220 as I've now defined them, a list of strings in this case, 00:39:28.220 --> 00:39:33.860 or using a for loop now to iterate over and print each of those names. 00:39:33.860 --> 00:39:34.550 AUDIENCE: Yeah. 00:39:34.550 --> 00:39:38.150 So is it not necessary to initiate student in this case? 00:39:38.150 --> 00:39:40.575 Or we can just declare a variable in the loop? 00:39:40.575 --> 00:39:41.700 DAVID MALAN: Good question. 00:39:41.700 --> 00:39:43.450 You do not need to manually initialize it. 00:39:43.450 --> 00:39:47.810 Python takes care of initializing the student variable to Hermione 00:39:47.810 --> 00:39:49.960 first, then Harry second, then Ron third. 00:39:49.960 --> 00:39:53.210 Unlike other languages, you don't need to initialize it to something yourself, 00:39:53.210 --> 00:39:55.250 it just exists and it will work. 00:39:55.250 --> 00:39:58.662 Other questions on loops and lists in this way? 00:39:58.662 --> 00:40:00.620 AUDIENCE: Since you describe break, so is there 00:40:00.620 --> 00:40:04.232 any concept of continuing so that we can skip a particular case in loops? 00:40:04.232 --> 00:40:04.940 DAVID MALAN: Yes. 00:40:04.940 --> 00:40:06.933 You can continue using another syntax as well. 00:40:06.933 --> 00:40:07.850 We haven't shown that. 00:40:07.850 --> 00:40:10.668 For now we focused only on break. 00:40:10.668 --> 00:40:11.210 AUDIENCE: OK. 00:40:11.210 --> 00:40:15.770 So can this for loop work with either hash tables or different kind 00:40:15.770 --> 00:40:17.607 of tables or arrays? 00:40:17.607 --> 00:40:18.440 DAVID MALAN: Indeed. 00:40:18.440 --> 00:40:20.190 So we're getting ahead of ourselves there, 00:40:20.190 --> 00:40:22.610 but there are yet other types of data in Python, 00:40:22.610 --> 00:40:26.550 and indeed, you can use a for loop to iterate over those as well. 00:40:26.550 --> 00:40:28.940 Anything that is iterable, so to speak, is 00:40:28.940 --> 00:40:32.030 a piece of data that can be used with a loop like this. 00:40:32.030 --> 00:40:34.290 But more on those-- more on those soon. 00:40:34.290 --> 00:40:37.967 In fact, let me transition here to show just another way of solving 00:40:37.967 --> 00:40:40.550 this same problem, because up until now when we've used loops, 00:40:40.550 --> 00:40:43.040 we really have relied on numbers, and that's fine 00:40:43.040 --> 00:40:45.620 if you prefer to stay in that space. 00:40:45.620 --> 00:40:49.610 Suppose I did want to iterate using numbers like i and 0, 00:40:49.610 --> 00:40:50.910 1, 2, and so forth. 00:40:50.910 --> 00:40:53.700 Let me propose that we could change this code as follows. 00:40:53.700 --> 00:40:56.930 If you would prefer to think about, or if the program you're 00:40:56.930 --> 00:40:59.810 trying to implement requires that you use numbers like this, 00:40:59.810 --> 00:41:00.830 you might do this. 00:41:00.830 --> 00:41:04.820 For i in-- well, I don't want to just say students, 00:41:04.820 --> 00:41:07.580 because then i is not going to be a number. 00:41:07.580 --> 00:41:13.010 i is going to be literally Hermione, then Harry, then Ron. 00:41:13.010 --> 00:41:17.030 I need to iterate from 0 to 1 to 2. 00:41:17.030 --> 00:41:21.320 If I a list with three elements has these locations, 0, 1, 2, 00:41:21.320 --> 00:41:25.400 I need to create a loop somehow that starts at 0 and ends at 2. 00:41:25.400 --> 00:41:28.340 Previously when I wanted to do that, I needed range, 00:41:28.340 --> 00:41:30.290 but this 2 is not going to work. 00:41:30.290 --> 00:41:32.750 I can't just say in the range of students, 00:41:32.750 --> 00:41:36.030 because students is not a number, it's not an integer, 00:41:36.030 --> 00:41:37.640 so you can't pass it to range. 00:41:37.640 --> 00:41:39.260 Range expects an integer. 00:41:39.260 --> 00:41:41.840 But there is a solution here. 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, 00:41:47.390 --> 00:41:51.890 that will tell you the length of a list and other things down the line, too. 00:41:51.890 --> 00:41:55.850 And now I think I can assemble these building blocks and a way that can 00:41:55.850 --> 00:41:57.740 allow me to use numbers in this way. 00:41:57.740 --> 00:42:02.870 So range doesn't take a list of strings, it takes a number, 00:42:02.870 --> 00:42:04.790 and ideally, that number is going to be 3, 00:42:04.790 --> 00:42:07.580 so I get a range of values, 0, 1, and 2. 00:42:07.580 --> 00:42:10.640 So I think I can nest my functions like this. 00:42:10.640 --> 00:42:15.410 If I first get the length of the students list, that's going to be 3, 00:42:15.410 --> 00:42:18.620 then I pass that return value as the argument 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. 00:42:23.840 --> 00:42:26.570 And what that's going to allow me to do then in code if I want 00:42:26.570 --> 00:42:28.310 is not just this. 00:42:28.310 --> 00:42:33.650 I could do print now students bracket i, and this is now 00:42:33.650 --> 00:42:38.270 where the syntax we're seeing is getting very expressive-- new and perhaps 00:42:38.270 --> 00:42:39.200 unfamiliar. 00:42:39.200 --> 00:42:44.090 But if I can do open bracket, 0, close bracket, or open bracket, 1, 00:42:44.090 --> 00:42:47.990 close bracket, or open bracket, 2, close bracket, turns out, 00:42:47.990 --> 00:42:49.940 I can actually put a variable in there and I 00:42:49.940 --> 00:42:52.490 can express any number inside of those brackets 00:42:52.490 --> 00:42:54.800 so as to print these all out dynamically in a loop. 00:42:54.800 --> 00:42:57.680 Let me do this, Python of hogwarts.py, Enter, 00:42:57.680 --> 00:43:00.140 there's Hermione, Harry, and Ron. 00:43:00.140 --> 00:43:02.570 And now if I'm just curious, I just want to poke 00:43:02.570 --> 00:43:05.060 around or maybe I want to do a ranking, like who 00:43:05.060 --> 00:43:08.240 are the top three students in the school or in Gryffindor? 00:43:08.240 --> 00:43:11.000 Well, I can print multiple things at a time, we've seen. 00:43:11.000 --> 00:43:14.540 Let me print out not just the students at location 00:43:14.540 --> 00:43:19.340 i, but rather, let's print i first and then the student at location i. 00:43:19.340 --> 00:43:22.850 So two things to print, and we know that print can take two arguments, 00:43:22.850 --> 00:43:25.280 we've seen that before, they'll be separated by a space. 00:43:25.280 --> 00:43:26.900 Let me go ahead and rerun this. 00:43:26.900 --> 00:43:31.533 Now I see that, OK, Hermione is the top student, but she's in zeroth place. 00:43:31.533 --> 00:43:32.450 That's a little weird. 00:43:32.450 --> 00:43:35.930 Like we don't need to show the human using my program 00:43:35.930 --> 00:43:37.430 that we started counting at 0. 00:43:37.430 --> 00:43:38.570 I can clean this up. 00:43:38.570 --> 00:43:41.600 I can just add 1 to the i up here, and now we 00:43:41.600 --> 00:43:43.640 see a top three list of students. 00:43:43.640 --> 00:43:47.540 Hermione is number 1, Harry's number 2, and of course, Ron is number 3. 00:43:47.540 --> 00:43:50.960 So we can get access to all of those same values as well. 00:43:50.960 --> 00:43:55.320 Are there any questions now on these lists? 00:43:55.320 --> 00:43:58.320 Any questions now on these lists? 00:43:58.320 --> 00:44:01.050 This length, these ranges, or otherwise? 00:44:01.050 --> 00:44:08.350 AUDIENCE: My question is, for i in range, can you explain this once more? 00:44:08.350 --> 00:44:10.210 DAVID MALAN: Sure. 00:44:10.210 --> 00:44:12.640 So let me rewind in time. 00:44:12.640 --> 00:44:13.960 We started off doing this. 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. 00:44:20.770 --> 00:44:23.830 The way that for loop works is that it creates 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. 00:44:27.730 --> 00:44:31.390 It then assigns i initially to the first thing in the list. 00:44:31.390 --> 00:44:34.690 It then automatically assigns i to the next thing in the list. 00:44:34.690 --> 00:44:37.210 And then it assigns i to the third thing in the list. 00:44:37.210 --> 00:44:41.520 And each time it does all of the indented code underneath. 00:44:41.520 --> 00:44:43.740 We realize, though, that this is not going 00:44:43.740 --> 00:44:46.380 to scale well if I want to do something like a million times. 00:44:46.380 --> 00:44:48.480 So we introduced range instead. 00:44:48.480 --> 00:44:51.240 That has the effect of doing the same thing. 00:44:51.240 --> 00:44:55.080 It returns to me a range of values-- a list of three things, really, 00:44:55.080 --> 00:44:57.330 so the behavior is exactly the same. 00:44:57.330 --> 00:45:01.890 If we now fast forward to this Hogwarts example now, though, what I'm doing 00:45:01.890 --> 00:45:04.500 is just combining these smaller ideas. 00:45:04.500 --> 00:45:06.330 I'm still creating a for loop. 00:45:06.330 --> 00:45:08.520 I'm still creating a variable called i. 00:45:08.520 --> 00:45:11.760 I want to do it over a range of values, but how many values? 00:45:11.760 --> 00:45:15.390 Well, if I use the length function and pass to the length function 00:45:15.390 --> 00:45:18.300 the list of values, length's purpose in life 00:45:18.300 --> 00:45:21.120 is to tell me how long is this list, and it's 3. 00:45:21.120 --> 00:45:25.740 So that's almost as though before, I had just done something like this, 00:45:25.740 --> 00:45:29.220 but I don't want to hardcode 3, I want to dynamically figure out 00:45:29.220 --> 00:45:30.870 how many students are at Hogwarts. 00:45:30.870 --> 00:45:32.910 So I'm just composing, composing, composing, 00:45:32.910 --> 00:45:36.210 or nesting all of these various ideas. 00:45:36.210 --> 00:45:38.880 All right, if I may, let me transition now to-- 00:45:38.880 --> 00:45:42.540 in Hogwarts still to introduce one final type of data before 00:45:42.540 --> 00:45:45.690 we combine everything with a few final programs. 00:45:45.690 --> 00:45:49.410 It turns out in Python, there's not just strings, not just 00:45:49.410 --> 00:45:51.600 ints, not just floating point values, not 00:45:51.600 --> 00:45:53.790 just bools, not just lists there are also 00:45:53.790 --> 00:45:58.560 what are called dictionaries or dics, are a data structure that allows you 00:45:58.560 --> 00:46:02.250 to associate one value with another. 00:46:02.250 --> 00:46:04.380 Literally a dictionary like in the human world. 00:46:04.380 --> 00:46:07.680 If you were to open a dictionary, be it in English or any other human language, 00:46:07.680 --> 00:46:09.190 what's inside of a dictionary? 00:46:09.190 --> 00:46:12.480 Well, it's a bunch of words and definitions. 00:46:12.480 --> 00:46:14.760 A computer scientist, though, and a programmer 00:46:14.760 --> 00:46:19.470 would describe those more generically as keys and values, something 00:46:19.470 --> 00:46:21.360 associated with something else. 00:46:21.360 --> 00:46:22.950 That's all a dictionary is. 00:46:22.950 --> 00:46:25.930 It allows you to associate something with something else. 00:46:25.930 --> 00:46:29.160 And notice, this is already more powerful, more interesting than a list. 00:46:29.160 --> 00:46:32.670 A list is just a set of multiple values. 00:46:32.670 --> 00:46:36.240 But a dictionary is two-dimensional, if you will. 00:46:36.240 --> 00:46:39.390 Just like a human dictionary, a book, it associates something 00:46:39.390 --> 00:46:42.210 with something else like words with their definitions. 00:46:42.210 --> 00:46:44.500 Now what does this actually mean in practice? 00:46:44.500 --> 00:46:48.390 Well suppose that we wanted to keep track 00:46:48.390 --> 00:46:51.810 of who is in what house at Hogwarts. 00:46:51.810 --> 00:46:54.240 Well, I could do it using lists alone. 00:46:54.240 --> 00:46:55.950 Let me go back to VS Code here and let me 00:46:55.950 --> 00:46:59.470 just temporarily-- but in a way that I'm not going to like ultimately-- 00:46:59.470 --> 00:47:01.620 let me create another variable called houses, 00:47:01.620 --> 00:47:06.750 set it equal to Gryffindor, corresponding to Hermione's house, 00:47:06.750 --> 00:47:09.960 Gryffindor, corresponding to Harry's house, and Gryffindor, 00:47:09.960 --> 00:47:11.250 corresponding to Ron's house. 00:47:11.250 --> 00:47:12.730 And let's add Draco in there. 00:47:12.730 --> 00:47:14.640 So we now have four instead of three students 00:47:14.640 --> 00:47:18.810 just so we have a little variety, and he was in Slytherin. 00:47:18.810 --> 00:47:21.300 So now we have two lists. 00:47:21.300 --> 00:47:24.750 And we could just agree amongst ourselves 00:47:24.750 --> 00:47:28.680 that whoever is first in the students variable lives 00:47:28.680 --> 00:47:31.410 in the first value in houses. 00:47:31.410 --> 00:47:34.770 Whoever is second in students lives in the second house. 00:47:34.770 --> 00:47:37.680 Who's ever third in students lives in the third house. 00:47:37.680 --> 00:47:38.730 We could do that. 00:47:38.730 --> 00:47:41.430 But honestly, that is going to break down quickly 00:47:41.430 --> 00:47:44.102 when we have a lot of students, when we have a lot of houses, 00:47:44.102 --> 00:47:46.560 and what if we want to keep track of more things than that? 00:47:46.560 --> 00:47:48.810 What if we want to keep track of every student's house 00:47:48.810 --> 00:47:52.890 and the patronus, this image that they conjure up magically? 00:47:52.890 --> 00:47:55.290 Well, then we need a third list like-- this is just 00:47:55.290 --> 00:47:58.440 going to get messy quickly if we're just on the honor system 00:47:58.440 --> 00:48:02.640 using multiple lists where everything lines up logically. 00:48:02.640 --> 00:48:05.940 It doesn't end up well when your code gets more complicated. 00:48:05.940 --> 00:48:07.740 But I do want to implement this idea. 00:48:07.740 --> 00:48:09.990 I want to associate something with something. 00:48:09.990 --> 00:48:12.960 A student with a house, a student with a house, a student with a house 00:48:12.960 --> 00:48:15.970 and so forth, so how can I go about doing this? 00:48:15.970 --> 00:48:18.570 Well, let me go back to my code here and let 00:48:18.570 --> 00:48:22.410 me propose that we do this using a Python dictionary. 00:48:22.410 --> 00:48:25.560 And this is the last of the new syntax, really, that we'll see . 00:48:25.560 --> 00:48:26.880 Here's the new syntax. 00:48:26.880 --> 00:48:29.280 Instead of using square brackets, we're going 00:48:29.280 --> 00:48:32.500 to use curly braces for dictionaries as well. 00:48:32.500 --> 00:48:37.050 We've seen curly braces in the context of f strings completely unrelated. 00:48:37.050 --> 00:48:40.360 Sometimes you run out of keys on the keyboard and the authors of a language 00:48:40.360 --> 00:48:43.302 need to start reusing symbols in different ways, that's 00:48:43.302 --> 00:48:44.260 what's about to happen. 00:48:44.260 --> 00:48:46.150 We're using curly braces in a different way. 00:48:46.150 --> 00:48:48.690 Now so let me create a variable called students. 00:48:48.690 --> 00:48:51.960 And let me go ahead and set it equal to open 00:48:51.960 --> 00:48:54.030 curly brace and closed curly brace. 00:48:54.030 --> 00:48:56.670 This is an empty dictionary at the moment. 00:48:56.670 --> 00:48:58.590 And here's how a dictionary works. 00:48:58.590 --> 00:49:01.150 It allows you to associate something with something else, 00:49:01.150 --> 00:49:02.400 and you do that like this. 00:49:02.400 --> 00:49:07.777 Hermione, quote-unquote, colon, and then the value thereof. 00:49:07.777 --> 00:49:09.610 What do you want to associate with Hermione? 00:49:09.610 --> 00:49:11.280 Well, Gryffindor. 00:49:11.280 --> 00:49:13.680 What do I want to associate Harry with? 00:49:13.680 --> 00:49:16.560 Well, I want to associate him with Gryffindor. 00:49:16.560 --> 00:49:18.630 What do I want to associate Ron with? 00:49:18.630 --> 00:49:21.240 Well, I want to associate him with Gryffindor. 00:49:21.240 --> 00:49:24.600 Well, this is actually not going to-- this is going to get very ugly quickly. 00:49:24.600 --> 00:49:27.502 Once we add in Draco and Slytherin, my code is going to get too long, 00:49:27.502 --> 00:49:28.710 it's going to start wrapping. 00:49:28.710 --> 00:49:30.390 So this is purely aesthetic. 00:49:30.390 --> 00:49:33.450 It is perfectly acceptable in Python and other languages 00:49:33.450 --> 00:49:36.570 to format your code a little more readily and just add new lines 00:49:36.570 --> 00:49:38.040 if it makes it more readable. 00:49:38.040 --> 00:49:40.480 And one way of doing this might be as follows. 00:49:40.480 --> 00:49:44.920 I still have my curly brace up here, I still have my curly brace down here, 00:49:44.920 --> 00:49:47.400 but notice, it's a little more readable now 00:49:47.400 --> 00:49:51.743 in that I have my keys on the left, my somethings, and my values 00:49:51.743 --> 00:49:53.160 on the right, my other somethings. 00:49:53.160 --> 00:49:55.800 It's just a little easier to skim top to bottom. 00:49:55.800 --> 00:49:57.480 You could format it differently as well. 00:49:57.480 --> 00:50:00.690 But I'm going to go ahead and add in now Draco 00:50:00.690 --> 00:50:03.210 who lives, of course, in Slytherin. 00:50:03.210 --> 00:50:07.320 So now I have each of these keys on the left 00:50:07.320 --> 00:50:09.910 and values on the right, which is really, again, 00:50:09.910 --> 00:50:13.200 just a code implementation of this idea, a little chart 00:50:13.200 --> 00:50:15.300 that you might write up with paper pencil 00:50:15.300 --> 00:50:17.620 when associating something with something else. 00:50:17.620 --> 00:50:20.680 So how do I now use this code in an interesting way? 00:50:20.680 --> 00:50:22.230 The syntax is almost the same. 00:50:22.230 --> 00:50:26.160 If I want to print out the very first student, Hermione's house, 00:50:26.160 --> 00:50:27.150 I could do this. 00:50:27.150 --> 00:50:31.960 Print out the name of the variable, but I need to go inside of the variable. 00:50:31.960 --> 00:50:33.810 I need to index into it. 00:50:33.810 --> 00:50:38.280 And what's neat about dictionaries is that whereas lists 00:50:38.280 --> 00:50:41.010 have locations that are numeric-- 00:50:41.010 --> 00:50:45.270 0, 1, 2; Hermione, Harry, Ron respectively, 00:50:45.270 --> 00:50:50.520 dictionaries allow you to use actual words as your indices, so to speak, 00:50:50.520 --> 00:50:52.750 your indexes to get inside of them. 00:50:52.750 --> 00:50:55.740 So if you want to print out Hermione's house, 00:50:55.740 --> 00:50:59.160 the key you care about is, quote-unquote, Hermione, 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. 00:51:04.050 --> 00:51:05.970 It's literally Hermione's name. 00:51:05.970 --> 00:51:11.070 This is like going to the chart earlier and saying, all right, give me Hermione 00:51:11.070 --> 00:51:13.628 is my key, Gryffindor is the value. 00:51:13.628 --> 00:51:15.420 That's what we're doing here syntactically. 00:51:15.420 --> 00:51:18.300 We're looking up Hermione and getting the value thereof. 00:51:18.300 --> 00:51:21.120 So if I go back to my code, that should print out Gryffindor. 00:51:21.120 --> 00:51:24.330 And if I do this a few times, students, bracket, quote-unquote, 00:51:24.330 --> 00:51:26.280 Harry should give me Harry's house. 00:51:26.280 --> 00:51:30.630 Print students, open bracket, Ron, that should give me Ron's house. 00:51:30.630 --> 00:51:33.660 And then lastly, if I do this with students, bracket, Draco, 00:51:33.660 --> 00:51:35.727 that should give me Draco's house. 00:51:35.727 --> 00:51:38.310 Now it's a little manual still, and I bet we can improve this, 00:51:38.310 --> 00:51:40.620 but let me run Python on hogwarts.py and we 00:51:40.620 --> 00:51:44.790 should see Gryffindor, Gryffindor, Gryffindor, Slytherin, which 00:51:44.790 --> 00:51:46.500 is exactly what we'd expect. 00:51:46.500 --> 00:51:48.810 Now all we've done, again, is we've just now moved 00:51:48.810 --> 00:51:52.710 from having just a simple list of names to, again, two dimensions, 00:51:52.710 --> 00:51:56.070 associating like we would on paper-pencil something with something 00:51:56.070 --> 00:51:58.920 else, keys with values respectively. 00:51:58.920 --> 00:52:02.580 Allow me, if you will, even though I realize this is getting a little fancy, 00:52:02.580 --> 00:52:07.200 allow me to escalate things slightly here and transition from looking 00:52:07.200 --> 00:52:13.020 at just, for instance, that pattern there, just a hard coding those values 00:52:13.020 --> 00:52:15.660 there to actually printing these out more dynamically. 00:52:15.660 --> 00:52:19.510 Let me go ahead and use our loop, and this question came up earlier as well, 00:52:19.510 --> 00:52:25.450 let me go ahead and say for each student in students, 00:52:25.450 --> 00:52:31.240 go ahead and print out, for instance, the students variable at-- 00:52:31.240 --> 00:52:32.920 well, let's just say student first. 00:52:32.920 --> 00:52:33.950 Let's keep it simple. 00:52:33.950 --> 00:52:35.950 So this is not going to be that interesting yet, 00:52:35.950 --> 00:52:41.470 but when I run Python of hogwarts.py and hit Enter, notice, what should I see? 00:52:41.470 --> 00:52:44.200 Let me take a question here to see what am I 00:52:44.200 --> 00:52:48.910 going to see when I hit Enter now when I'm doing for student in students? 00:52:48.910 --> 00:52:51.305 AUDIENCE: Yeah, I think we will only see keys. 00:52:51.305 --> 00:52:52.180 DAVID MALAN: Perfect. 00:52:52.180 --> 00:52:53.020 So good intuition. 00:52:53.020 --> 00:52:53.980 It could have gone both ways. 00:52:53.980 --> 00:52:55.540 Could have been values, the houses. 00:52:55.540 --> 00:53:01.300 But when you use a for loop in Python to iterate over a dictionary, by design, 00:53:01.300 --> 00:53:03.550 it iterates over all of the keys. 00:53:03.550 --> 00:53:07.960 So we should see, I think, Hermione, Harry, Ron, and Draco. 00:53:07.960 --> 00:53:11.260 Let me hit Enter now, Enter, and indeed, you're exactly right, 00:53:11.260 --> 00:53:12.580 we see just the keys. 00:53:12.580 --> 00:53:15.580 But that's not really that useful if what I really care about 00:53:15.580 --> 00:53:18.430 is who lives where, can I print out both? 00:53:18.430 --> 00:53:19.930 Well, I think I can. 00:53:19.930 --> 00:53:21.350 Let me go ahead and do this. 00:53:21.350 --> 00:53:24.850 Let me print out not just the student's name, the key, 00:53:24.850 --> 00:53:30.537 but let me use the key, their name, to index into the dictionary. 00:53:30.537 --> 00:53:33.370 If I know the word in the dictionary, let me look up its definition. 00:53:33.370 --> 00:53:35.980 If I know the student's name, let me look up their house, 00:53:35.980 --> 00:53:40.720 and the syntax for this, just like a list, is students, bracket. 00:53:40.720 --> 00:53:44.480 And just like in the past we used i when i was a number, 00:53:44.480 --> 00:53:48.080 we can also with a dictionary use a string. 00:53:48.080 --> 00:53:55.180 So if the student's name is the key, then this syntax, students, 00:53:55.180 --> 00:54:00.340 open bracket, student, close bracket will go to Hermione's location 00:54:00.340 --> 00:54:01.330 and get back her house. 00:54:01.330 --> 00:54:04.970 Will go to Harry's location and get back his house and so forth. 00:54:04.970 --> 00:54:08.943 So if I do Python of hogwarts.py, Enter, now I 00:54:08.943 --> 00:54:11.485 see Hermione, Gryffindor; Harry, Gryffindor; Ron, Gryffindor; 00:54:11.485 --> 00:54:12.730 and Draco Slytherin. 00:54:12.730 --> 00:54:14.940 Now it looks like I've given them all new last names, 00:54:14.940 --> 00:54:15.940 but I can clean that up. 00:54:15.940 --> 00:54:17.170 This is just a print thing. 00:54:17.170 --> 00:54:20.110 Let's go ahead and change our separator from the default space 00:54:20.110 --> 00:54:21.790 to maybe a space, comma. 00:54:21.790 --> 00:54:26.110 And just using print features now, let me run the same program again, Enter, 00:54:26.110 --> 00:54:29.050 now I've just got some nice pretty commas in there to make clear 00:54:29.050 --> 00:54:31.810 that Hermione's last name is not, in fact, Gryffindor, 00:54:31.810 --> 00:54:33.730 but that's just a print detail. 00:54:33.730 --> 00:54:37.120 Any questions, then, on these dictionaries and what I've just done? 00:54:39.650 --> 00:54:45.410 Questions on these dictionaries and this looping over then here? 00:54:45.410 --> 00:54:52.190 AUDIENCE: I just can't get my head around the for student in students. 00:54:52.190 --> 00:54:54.860 If I'm-- just correct me if I'm right. 00:54:54.860 --> 00:55:01.850 Does that mean it imports the list of students and uses the indexes-- 00:55:01.850 --> 00:55:09.140 or in other words, Hermione, Harry, and Ron as the indexes in the actual-- 00:55:09.140 --> 00:55:10.455 the list of students? 00:55:10.455 --> 00:55:11.330 DAVID MALAN: Correct. 00:55:11.330 --> 00:55:13.100 So this is just a feature of Python. 00:55:13.100 --> 00:55:17.150 When you use a for loop with a dictionary, what happens is this. 00:55:17.150 --> 00:55:20.513 If this is the dictionary here with the keys on top and the values on bottom, 00:55:20.513 --> 00:55:22.430 you get to choose what the variable is called. 00:55:22.430 --> 00:55:24.818 I called my variable student just because it makes sense, 00:55:24.818 --> 00:55:26.360 because I want one student at a time. 00:55:26.360 --> 00:55:29.510 And what for loop does, just like it did with numbers before, 00:55:29.510 --> 00:55:33.060 the 0, the 1, and the 2, it allows me to, for instance, 00:55:33.060 --> 00:55:35.810 set student equal initially to Hermelin's name. 00:55:35.810 --> 00:55:38.990 And then the next iteration of the loop, the next cycle, 00:55:38.990 --> 00:55:42.800 sets student equal to Harry's name, then Ron, then Draco. 00:55:42.800 --> 00:55:44.300 It just happens automatically. 00:55:44.300 --> 00:55:47.480 Like that is what the Python interpreter does for you when 00:55:47.480 --> 00:55:49.140 it sees a for loop like that. 00:55:49.140 --> 00:55:53.090 So it's very similar in spirit to iterating with a for loop over a list, 00:55:53.090 --> 00:55:55.670 but rather than iterate over the numeric location, 00:55:55.670 --> 00:56:01.700 0, 1, 2, it iterates over the bold-faced keys in this representation here 00:56:01.700 --> 00:56:02.930 graphically. 00:56:02.930 --> 00:56:05.960 And allow me to give us one other example on Hogwarts 00:56:05.960 --> 00:56:09.320 before we look at one other familiar domain. 00:56:09.320 --> 00:56:11.670 At the risk of things escalating a little bit, 00:56:11.670 --> 00:56:15.320 let me propose that we continue the story with one final Hogwarts 00:56:15.320 --> 00:56:17.100 example like this. 00:56:17.100 --> 00:56:21.280 What if we have more information about each of our students? 00:56:21.280 --> 00:56:23.030 And this is inevitable. 00:56:23.030 --> 00:56:26.760 If you're implementing a program that's a database with people or customers, 00:56:26.760 --> 00:56:29.060 or employees or anything else, you can imagine 00:56:29.060 --> 00:56:33.230 having a lot of data about anything you're representing in your program 00:56:33.230 --> 00:56:33.740 here. 00:56:33.740 --> 00:56:37.470 For the sake of discussion, suppose that every student at Hogwarts, of course, 00:56:37.470 --> 00:56:41.480 has a name, they have already a house, but they also have a patronus. 00:56:41.480 --> 00:56:44.360 For those unfamiliar, this is the animal or entity 00:56:44.360 --> 00:56:48.260 that comes out of the end of their wand when they make a certain magical spell. 00:56:48.260 --> 00:56:51.410 The point here being is that we want to associate not 00:56:51.410 --> 00:56:55.670 just one thing with the student, but multiple things 00:56:55.670 --> 00:57:00.110 as well-- their name, their house, and their patronus in this case. 00:57:00.110 --> 00:57:02.400 Well, what might code like this look like? 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. 00:57:07.100 --> 00:57:10.650 And let me propose that I enhance this with a bit more data. 00:57:10.650 --> 00:57:12.800 And this data is going to look as follows. 00:57:12.800 --> 00:57:18.360 My students variable now, I'm going to propose we think of it as a list. 00:57:18.360 --> 00:57:21.320 What if we have a list of dictionaries as follows? 00:57:21.320 --> 00:57:24.960 Indeed I want to literally implement this picture here. 00:57:24.960 --> 00:57:29.210 So notice that my previous picture just represented a single dictionary. 00:57:29.210 --> 00:57:33.500 But suppose I wanted to compose a list of dictionaries. 00:57:33.500 --> 00:57:36.650 That is, for students-- so a list of four students. 00:57:36.650 --> 00:57:41.240 And suppose that each of those students is itself a dictionary, 00:57:41.240 --> 00:57:46.130 a collection of key value pairs, keys and values, 00:57:46.130 --> 00:57:48.180 something and something else. 00:57:48.180 --> 00:57:50.990 Well, here's one other way we can do this in code. 00:57:50.990 --> 00:57:55.130 Let me go back to VS Code here and let me define a variable called 00:57:55.130 --> 00:57:58.100 students that is equal to a list. 00:57:58.100 --> 00:58:01.343 And I'm going to preemptively move my cursor onto separate lines, 00:58:01.343 --> 00:58:03.260 because I know this is going to be long, and I 00:58:03.260 --> 00:58:07.320 want to fit all of the elements of this list inside of it. 00:58:07.320 --> 00:58:10.555 I'm now going to create a dictionary, one dictionary per student. 00:58:10.555 --> 00:58:11.930 And how do I create a dictionary? 00:58:11.930 --> 00:58:13.670 I just use those curly braces. 00:58:13.670 --> 00:58:16.220 But it's up to me to define what those keys are. 00:58:16.220 --> 00:58:18.500 And let me propose that one key this time 00:58:18.500 --> 00:58:20.750 won't be the student's name explicitly, it 00:58:20.750 --> 00:58:24.980 will literally be the word name, and there, going to have the name Hermione. 00:58:24.980 --> 00:58:28.700 The same student is going to have another key called house 00:58:28.700 --> 00:58:31.010 and the value is going to be Gryffindor. 00:58:31.010 --> 00:58:34.700 And the same student is going to have a third key called patronus, 00:58:34.700 --> 00:58:36.620 and the value of that is going to be-- 00:58:36.620 --> 00:58:39.710 I had to look it up-- an otter, according to the book. 00:58:39.710 --> 00:58:43.012 Now I'm going to create a second dictionary inside of this list. 00:58:43.012 --> 00:58:44.720 And again, a dictionary is like literally 00:58:44.720 --> 00:58:46.710 like the human dictionary of words. 00:58:46.710 --> 00:58:50.750 It's a book that contains keys and values, words and definitions. 00:58:50.750 --> 00:58:53.630 What are the three words I'm storing in each of my dictionaries? 00:58:53.630 --> 00:58:55.640 Name, house, and patronus. 00:58:55.640 --> 00:58:58.940 What are the definitions of those words for Hermione? 00:58:58.940 --> 00:59:01.850 Hermione, Gryffindor, and otter respectively. 00:59:01.850 --> 00:59:05.840 For Harry, the definitions are going to be different in this new dictionary. 00:59:05.840 --> 00:59:08.270 Let me give myself another pair of curly braces 00:59:08.270 --> 00:59:12.230 and say this, name, quote-unquote, colon, Harry. 00:59:12.230 --> 00:59:15.500 House here is, again, going to be Gryffindor. 00:59:15.500 --> 00:59:21.620 And this one I knew, his patronus, is going to be, in this case, a stag. 00:59:21.620 --> 00:59:23.330 Next, a third dictionary. 00:59:23.330 --> 00:59:25.130 The name here will be Ron. 00:59:25.130 --> 00:59:27.560 And I'm going to go ahead and do that just like this. 00:59:27.560 --> 00:59:31.070 Next, I have the house, and he, too, was Gryffindor. 00:59:31.070 --> 00:59:38.120 Lastly, had to look this one up, Ron's patronus was a Jack Russell terrier. 00:59:38.120 --> 00:59:42.100 Lastly is Draco. 00:59:42.100 --> 00:59:45.070 In a fourth dictionary now-- so another pair of curly braces, 00:59:45.070 --> 00:59:47.380 the name of the student is, of course, Draco. 00:59:47.380 --> 00:59:50.650 The house of this student is Slytherin. 00:59:50.650 --> 00:59:55.630 And Draco, interestingly enough, at least according to the internet, 00:59:55.630 --> 00:59:57.010 has no patronus. 00:59:57.010 --> 00:59:59.230 Was never revealed in the books or the movies. 00:59:59.230 --> 01:00:02.290 So it turns out, this is actually a wonderful teachable moment. 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, 01:00:08.170 --> 01:00:10.360 with the first letter capitalized. 01:00:10.360 --> 01:00:14.210 This represents officially the absence of a value. 01:00:14.210 --> 01:00:17.440 So I could a little sloppily do something like quote-unquote, 01:00:17.440 --> 01:00:20.410 but does that mean I didn't get around to typing it or not? 01:00:20.410 --> 01:00:24.880 It's a little clear semantically to say literally None, a special keyword 01:00:24.880 --> 01:00:29.620 in Python to make clear that I know Draco has no patronus, 01:00:29.620 --> 01:00:32.320 it's not just an oversight on my part. 01:00:32.320 --> 01:00:36.370 Now that I have this, what do I have in the computer's memory? 01:00:36.370 --> 01:00:37.360 I have a list. 01:00:37.360 --> 01:00:38.620 How do I know it's a list? 01:00:38.620 --> 01:00:42.310 Because I see a square bracket at the beginning and another square bracket 01:00:42.310 --> 01:00:42.850 at the end. 01:00:42.850 --> 01:00:45.730 That's just my visual clue, OK, I don't know necessarily 01:00:45.730 --> 01:00:48.910 what else is going on here, but there's a list of something. 01:00:48.910 --> 01:00:50.960 What is in that list? 01:00:50.960 --> 01:00:53.560 Well, here, too, the syntax is our clue. 01:00:53.560 --> 01:00:57.820 Because this line 2 starts with a curly brace and ends with a curly brace, 01:00:57.820 --> 01:01:02.570 I just know, that is a dictionary, a collection of key value pairs. 01:01:02.570 --> 01:01:04.930 Now this all fit on my screen perfectly, so I 01:01:04.930 --> 01:01:08.020 didn't bother moving all of the key value pairs onto new lines, 01:01:08.020 --> 01:01:11.620 it would have made it really tall, so I kept it all together here this time. 01:01:11.620 --> 01:01:15.520 But how many keys does this first dictionary have? 01:01:15.520 --> 01:01:17.897 Put another way, in Hermione's physical dictionary, 01:01:17.897 --> 01:01:19.480 how many words are in that dictionary? 01:01:19.480 --> 01:01:20.230 Three. 01:01:20.230 --> 01:01:22.990 The words are name, house, and patronus. 01:01:22.990 --> 01:01:26.140 What are the three definitions or values of those words 01:01:26.140 --> 01:01:27.640 in Hermione's dictionary? 01:01:27.640 --> 01:01:31.000 Hermione, Gryffindor, and otter respectively. 01:01:31.000 --> 01:01:35.360 And the same story goes for Harry, then for Ron, 01:01:35.360 --> 01:01:39.190 then for Draco, I have, by design, chosen 01:01:39.190 --> 01:01:44.440 to give them dictionaries that have all the same keys, all the same names, 01:01:44.440 --> 01:01:47.200 but they all have unique values. 01:01:47.200 --> 01:01:50.080 And that's my design, that's my prerogative as a programmer. 01:01:50.080 --> 01:01:53.200 So why is this useful at the end of the day now? 01:01:53.200 --> 01:01:57.130 I have access to a whole collection of interesting data about all 01:01:57.130 --> 01:01:59.620 of these students, and I can still do a loop. 01:01:59.620 --> 01:02:02.980 I can say for students in students, that's 01:02:02.980 --> 01:02:05.590 going to allow me to iterate over this list of students. 01:02:05.590 --> 01:02:08.240 And let me go ahead and print out just one thing at a time. 01:02:08.240 --> 01:02:10.610 Let me print out the current student's name. 01:02:10.610 --> 01:02:14.470 So as complicated as the dictionary is, this should be pretty comfortable. 01:02:14.470 --> 01:02:18.490 For student in students is just going to iterate over every student in the list. 01:02:18.490 --> 01:02:20.420 1, 2, 3, 4 total. 01:02:20.420 --> 01:02:24.580 The next line is just going to print out the value of the name key. 01:02:24.580 --> 01:02:27.850 It's like opening a physical dictionary, looking up the word name, 01:02:27.850 --> 01:02:30.670 and giving us Hermione, Harry, Ron, and Draco 01:02:30.670 --> 01:02:32.480 respectively from each dictionary. 01:02:32.480 --> 01:02:36.880 So if I run this version of Hogwarts and hit Enter, there, I get all three 01:02:36.880 --> 01:02:37.780 of their names. 01:02:37.780 --> 01:02:39.790 But what if I want more information than that? 01:02:39.790 --> 01:02:42.040 I want both their names and their houses. 01:02:42.040 --> 01:02:47.650 Well, just add to print's arguments student, open bracket, house, 01:02:47.650 --> 01:02:48.910 close bracket. 01:02:48.910 --> 01:02:50.740 All right, let's go ahead and run this. 01:02:50.740 --> 01:02:53.170 Python of hogwarts.py and hit Enter. 01:02:53.170 --> 01:02:56.078 So I now see Hermione, Gryffindor; Harry, Gryffindor; and so forth. 01:02:56.078 --> 01:02:58.120 Well, we can aesthetically clean this up a little 01:02:58.120 --> 01:03:01.480 bit by adding a separator with print, like a comma and a space, 01:03:01.480 --> 01:03:03.760 just so that when I run this again, I now 01:03:03.760 --> 01:03:05.680 see some comma separating these values. 01:03:05.680 --> 01:03:08.290 But recall that students have not just a name, not just 01:03:08.290 --> 01:03:09.910 a house, but also that patronus. 01:03:09.910 --> 01:03:12.700 So if we want to print out that, too, we now 01:03:12.700 --> 01:03:18.040 have the syntax via which to go into that same dictionary for each student 01:03:18.040 --> 01:03:22.010 and output their patronus as well as their house in their name. 01:03:22.010 --> 01:03:24.520 So if I run this program one final time, now I 01:03:24.520 --> 01:03:28.490 see all of the data in this here dictionary. 01:03:28.490 --> 01:03:31.390 So this is a lot to absorb all at once, I'm sure. 01:03:31.390 --> 01:03:33.367 It's the last of our new data types. 01:03:33.367 --> 01:03:35.200 On top of lists, we have these dictionaries, 01:03:35.200 --> 01:03:37.750 but again, a dictionary, at the end of the day, 01:03:37.750 --> 01:03:41.740 is just a collection of values similar to these values 01:03:41.740 --> 01:03:44.780 here that allow you to associate keys with values. 01:03:44.780 --> 01:03:48.520 And the first version of this program associated literally the student's 01:03:48.520 --> 01:03:51.040 names with their houses, but then I realized 01:03:51.040 --> 01:03:53.920 in my next version, wait a minute, what if every student has not 01:03:53.920 --> 01:03:55.990 just a name in a house, but a patronus? 01:03:55.990 --> 01:03:59.230 Let's actually standardize the names of our keys 01:03:59.230 --> 01:04:03.850 to be name, house, and patronus, and then the values of those keys 01:04:03.850 --> 01:04:08.530 can actually be the data, like Hermione, Gryffindor, otter, and so forth. 01:04:08.530 --> 01:04:13.240 Questions now on these dictionaries and iteration thereof? 01:04:13.240 --> 01:04:18.710 AUDIENCE: I just was wondering, suppose the dictionary is very huge, 01:04:18.710 --> 01:04:22.270 and if I want to look up for a specific student, 01:04:22.270 --> 01:04:26.650 so how do I know where to look that student from? 01:04:26.650 --> 01:04:29.470 Like can we sort it out in alphabetical order 01:04:29.470 --> 01:04:32.163 or numeric order or anything like that? 01:04:32.163 --> 01:04:33.580 DAVID MALAN: In short answer, yes. 01:04:33.580 --> 01:04:37.570 One of the features of Python is that it makes these dictionaries very highly 01:04:37.570 --> 01:04:38.680 performant for you. 01:04:38.680 --> 01:04:42.280 That is, even if they're very large, as they will be in future weeks 01:04:42.280 --> 01:04:45.910 when we manipulate more data, Python will find the data 01:04:45.910 --> 01:04:48.520 you care about quickly for you. 01:04:48.520 --> 01:04:50.650 And in fact, that is a feature of the language, 01:04:50.650 --> 01:04:53.560 that is a feature of a dictionary to get you the data quickly. 01:04:53.560 --> 01:04:55.480 And there are functions that you can use. 01:04:55.480 --> 01:04:57.550 You can sort the data, you can sift through it, 01:04:57.550 --> 01:05:01.870 you can do very performant operations as we eventually will. 01:05:01.870 --> 01:05:05.800 Allow me, then, to propose, as we wrap up these loops, 01:05:05.800 --> 01:05:08.740 that we solve just a few final problems that will perhaps 01:05:08.740 --> 01:05:11.050 evoke fond memories of yesteryear, at least 01:05:11.050 --> 01:05:13.540 for me, wherein one of my favorite games growing up 01:05:13.540 --> 01:05:15.850 was this one here on the original Nintendo. 01:05:15.850 --> 01:05:19.240 And this is a two-dimensional world where the characters move up, 01:05:19.240 --> 01:05:23.020 down, and right, not so much to the left, in jumping over 01:05:23.020 --> 01:05:25.060 pyramids and obstructions like these. 01:05:25.060 --> 01:05:27.670 And allow me to propose that we use this just for inspiration, 01:05:27.670 --> 01:05:31.180 not to do something that's quite as colorful or graphical as this, but just 01:05:31.180 --> 01:05:34.990 to focus on, for instance, this barrier in the middle of the world 01:05:34.990 --> 01:05:38.080 here that Mario or Luigi had to jump over. 01:05:38.080 --> 01:05:42.372 And so this here seems to be like three bricks stepped on top of one another. 01:05:42.372 --> 01:05:44.080 And we won't do things quite graphically, 01:05:44.080 --> 01:05:48.190 but let's just implement a very simple Python-based version of this textually 01:05:48.190 --> 01:05:50.440 using maybe just hashes for bricks. 01:05:50.440 --> 01:05:53.500 Because there's a pattern here, one on top of the other, and I 01:05:53.500 --> 01:05:56.170 bet we can solve this in any number of ways. 01:05:56.170 --> 01:05:58.720 Well, let me switch back over to VS Code here 01:05:58.720 --> 01:06:03.340 and let me propose that we create a program called mario.py using code 01:06:03.340 --> 01:06:04.750 in the terminal window. 01:06:04.750 --> 01:06:07.630 And then up here, let me start by implementing that same picture 01:06:07.630 --> 01:06:11.590 as simply as I can, printing out just literally the hash, 01:06:11.590 --> 01:06:14.830 and then the hash, and then a third final hash. 01:06:14.830 --> 01:06:17.500 This is going to be a very textual approximation of it, 01:06:17.500 --> 01:06:20.440 but I think if I run Python mario.py, I've 01:06:20.440 --> 01:06:25.840 got a very simple version of that same column of bricks, so to speak. 01:06:25.840 --> 01:06:28.150 But you can imagine that certainly in a game 01:06:28.150 --> 01:06:31.380 where maybe these columns get higher or lower, 01:06:31.380 --> 01:06:33.880 it would be nice to write code that's actually a little more 01:06:33.880 --> 01:06:37.690 dynamic than that and doesn't just use print, print, print, which is literally 01:06:37.690 --> 01:06:39.340 copy and paste, it would seem. 01:06:39.340 --> 01:06:42.550 So let me at least adopt some of today's lessons 01:06:42.550 --> 01:06:44.650 learned and instead do something like this. 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. 01:06:50.620 --> 01:06:53.230 But the fact that I've now used a 3 to range 01:06:53.230 --> 01:06:55.840 means if I want to change it to something bigger or smaller, 01:06:55.840 --> 01:06:59.350 I change it in one place not in three or more places. 01:06:59.350 --> 01:07:01.450 And this code, too, of course, if I got it right, 01:07:01.450 --> 01:07:05.150 is just going to print out the exact same thing. 01:07:05.150 --> 01:07:06.610 So we're iterating here. 01:07:06.610 --> 01:07:08.860 But let's see if we can't now integrate our discussion 01:07:08.860 --> 01:07:13.420 of writing functions of our own to begin writing something a little more dynamic 01:07:13.420 --> 01:07:16.180 and solving more complicated problems ultimately. 01:07:16.180 --> 01:07:18.130 One of the nice things about functions is 01:07:18.130 --> 01:07:21.550 that they allow us to not just write code that we can use and reuse, 01:07:21.550 --> 01:07:24.640 they allow us to create abstractions, if you will. 01:07:24.640 --> 01:07:28.990 An abstraction is a simplification of a potentially more complicated idea. 01:07:28.990 --> 01:07:31.870 And we've seen this a few times over the course of the weeks. 01:07:31.870 --> 01:07:35.650 For instance, we had a function called hello, which, granted, didn't do 01:07:35.650 --> 01:07:37.480 all that much, it just printed hello. 01:07:37.480 --> 01:07:40.960 But it allowed me to think about the function as exactly what it does, 01:07:40.960 --> 01:07:44.590 not generically printing something, but literally saying hello. 01:07:44.590 --> 01:07:48.520 I've been able to get a number using something similar by defining 01:07:48.520 --> 01:07:50.320 my own function like get number. 01:07:50.320 --> 01:07:53.650 Well let me go ahead and, for instance, assume for the moment 01:07:53.650 --> 01:07:57.160 that I've had the forethought to, in my function main, 01:07:57.160 --> 01:07:59.770 use a function called print column. 01:07:59.770 --> 01:08:03.190 That seems as good a name as any to use a function that 01:08:03.190 --> 01:08:05.290 prints a column of bricks. 01:08:05.290 --> 01:08:07.660 Well, how can I go about now implementing 01:08:07.660 --> 01:08:12.100 this abstraction, this simple idea of print column with actual code? 01:08:12.100 --> 01:08:14.500 Well, we've seen before with def, we can do just that. 01:08:14.500 --> 01:08:16.720 Let me define a function called print column. 01:08:16.720 --> 01:08:21.220 Let me accept as its input, generically speaking, a parameter called height. 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 01:08:25.029 --> 01:08:27.250 just so I remind myself what it's doing. 01:08:27.250 --> 01:08:30.819 And now I think I can just borrow some of that same code from before. 01:08:30.819 --> 01:08:37.990 For underscore n range of height, go ahead and print out a single hash. 01:08:37.990 --> 01:08:41.050 And then at the end of this whole program, let's just call main. 01:08:41.050 --> 01:08:43.120 So I've kind of complicated the code. 01:08:43.120 --> 01:08:45.580 It doesn't do anything more just yet, but it's 01:08:45.580 --> 01:08:48.310 setting me up for solving what I think are going 01:08:48.310 --> 01:08:50.080 to be more sophisticated problems. 01:08:50.080 --> 01:08:53.170 If I run Python of mario.py, we're back where we began. 01:08:53.170 --> 01:08:57.520 But I now have a function, an abstraction, print column, 01:08:57.520 --> 01:09:00.040 that's going to allow me to think about printing 01:09:00.040 --> 01:09:03.432 some chunk of the world of Mario at a time. 01:09:03.432 --> 01:09:05.140 And I can do this in different ways, too. 01:09:05.140 --> 01:09:09.080 Notice that if I really want, I could do something like this. 01:09:09.080 --> 01:09:12.260 I could implement now print column in different ways, 01:09:12.260 --> 01:09:15.260 especially if I am using print column all over my code, 01:09:15.260 --> 01:09:19.220 or maybe still, a colleague of mine, a friend, someone else on the internet 01:09:19.220 --> 01:09:21.200 is using my print column function. 01:09:21.200 --> 01:09:23.899 What's also nice about functions you've written 01:09:23.899 --> 01:09:27.770 is you can change the underlying implementation details of them, 01:09:27.770 --> 01:09:31.850 but so long as you don't change the name of the function or its parameters 01:09:31.850 --> 01:09:35.870 or what it returns, if anything no one else knows the difference. 01:09:35.870 --> 01:09:37.970 You can change the internal implementation 01:09:37.970 --> 01:09:41.760 as much as you want if you want to improve it or make fixes over time. 01:09:41.760 --> 01:09:44.390 So for instance, another way we could implement print column, 01:09:44.390 --> 01:09:46.340 recall, would be something like this. 01:09:46.340 --> 01:09:48.920 A bit clever with one hash and then a new line, 01:09:48.920 --> 01:09:51.750 and then maybe we could do multiplication of strings, 01:09:51.750 --> 01:09:54.080 and then end this line with quote-unquote. 01:09:54.080 --> 01:09:57.110 Again, it's OK if you're not comfortable with this syntax. 01:09:57.110 --> 01:09:59.660 This was a more clever approach we saw in the past. 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. 01:10:04.280 --> 01:10:07.040 But what's important here is that main does not 01:10:07.040 --> 01:10:12.110 need to know that the underlying implementation of print column 01:10:12.110 --> 01:10:13.980 has changed. 01:10:13.980 --> 01:10:15.980 Well, let's transition to a different dimension, 01:10:15.980 --> 01:10:19.400 if you will, and rather than print out just these vertical bricks, let's 01:10:19.400 --> 01:10:22.160 fast forward in the game to this part of the world here. 01:10:22.160 --> 01:10:25.490 At some part, Mario encounters these bricks in the sky, 01:10:25.490 --> 01:10:27.690 that if he jumps up underneath, they become coins. 01:10:27.690 --> 01:10:29.780 And so he gains to his score. 01:10:29.780 --> 01:10:32.270 But let's go ahead and focus only on those coins, 01:10:32.270 --> 01:10:34.460 and let me propose that we print out, oh, just 01:10:34.460 --> 01:10:36.110 these four question marks here. 01:10:36.110 --> 01:10:38.150 And let me go back to VS Code here. 01:10:38.150 --> 01:10:41.480 And let me propose that within VS Code here, just like before, we 01:10:41.480 --> 01:10:43.010 try to abstract this away. 01:10:43.010 --> 01:10:45.290 So let me go ahead and get rid of this version, 01:10:45.290 --> 01:10:49.520 because we're now going horizontal instead of vertical with our output. 01:10:49.520 --> 01:10:53.690 And let me just say, well, print row four times. 01:10:53.690 --> 01:10:56.360 Let me just abstract away the problem at hand. 01:10:56.360 --> 01:10:59.180 I don't know yet how I'm going to print those four question marks, 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. 01:11:03.770 --> 01:11:06.800 Let's now go down that rabbit hole of solving the problem. 01:11:06.800 --> 01:11:09.020 Define a function called print row. 01:11:09.020 --> 01:11:11.570 It's going to take a width instead of a height, 01:11:11.570 --> 01:11:14.030 because it's horizontal instead of vertical. 01:11:14.030 --> 01:11:15.750 And how can I do this? 01:11:15.750 --> 01:11:19.160 Well now, we have an opportunity to do string multiplication even more 01:11:19.160 --> 01:11:19.760 elegantly. 01:11:19.760 --> 01:11:23.300 I can say quote-unquote, question mark, times width. 01:11:23.300 --> 01:11:28.010 And this is a very pretty Pythonic way of printing what could otherwise 01:11:28.010 --> 01:11:29.990 be a loop, and that's fine, but this is going 01:11:29.990 --> 01:11:32.630 to go ahead and print those question marks for me. 01:11:32.630 --> 01:11:37.130 Let's do Python of mario.py, Enter, and now I've got four question marks. 01:11:37.130 --> 01:11:39.530 It's not nearly as pretty as the more graphical version, 01:11:39.530 --> 01:11:44.390 but it is at least a building block toward having 01:11:44.390 --> 01:11:47.870 now a reusable function like print row. 01:11:47.870 --> 01:11:49.130 And why am I doing all this? 01:11:49.130 --> 01:11:52.820 Like why are we over engineering the solution to these problems 01:11:52.820 --> 01:11:54.920 by having print column and print row? 01:11:54.920 --> 01:11:57.620 Well, it's a useful problem-solving technique. 01:11:57.620 --> 01:12:00.410 As soon as your world does not look one-dimensional 01:12:00.410 --> 01:12:04.130 like this or with the column version, but what about this? 01:12:04.130 --> 01:12:08.270 Later in Super Mario Brothers does Mario have to jump down into this world 01:12:08.270 --> 01:12:11.000 where there's a lot of these underworld barriers. 01:12:11.000 --> 01:12:13.400 And this one here, for instance, looks like a square. 01:12:13.400 --> 01:12:16.400 It's two-dimensional there's a height and a width to it. 01:12:16.400 --> 01:12:18.830 And that is to say there's a bunch of different ways 01:12:18.830 --> 01:12:21.980 we could implement this thing if, maybe for discussion, 01:12:21.980 --> 01:12:26.780 it's like a 3-by-3 grid, a 3-by-3 square of sorts. 01:12:26.780 --> 01:12:29.570 Well, how can we go about solving this here problem? 01:12:29.570 --> 01:12:32.060 Well, let me propose we come back to VS Code 01:12:32.060 --> 01:12:36.420 and let me propose that we think about this in a couple of different ways. 01:12:36.420 --> 01:12:39.740 I could do this like this. 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 01:12:44.450 --> 01:12:45.060 and do this. 01:12:45.060 --> 01:12:48.530 Let me print out a square, the width, and the height of which is 3. 01:12:48.530 --> 01:12:49.487 That's an abstraction. 01:12:49.487 --> 01:12:52.070 I'm just taking for granted for a moment that there is already 01:12:52.070 --> 01:12:56.180 a function called print square that's going to be with 3 and height 3 01:12:56.180 --> 01:12:57.068 as well. 01:12:57.068 --> 01:12:59.360 But someone's got to implement this, and at the moment, 01:12:59.360 --> 01:13:01.580 there's only me at the keyboard, so let's go ahead 01:13:01.580 --> 01:13:03.020 and implement that square. 01:13:03.020 --> 01:13:05.000 Let me go ahead and define a function called 01:13:05.000 --> 01:13:10.250 print square that takes in a specific size, both for height and for width. 01:13:10.250 --> 01:13:13.310 And here's where we have an opportunity to use some of those loops. 01:13:13.310 --> 01:13:16.250 And we can use those loops in a way we haven't yet. 01:13:16.250 --> 01:13:21.500 If I want to print out all of these rows, but also, all of these columns, 01:13:21.500 --> 01:13:24.620 I now have to think not just cyclically like a loop allows, 01:13:24.620 --> 01:13:26.960 but I need to think two-dimensionally. 01:13:26.960 --> 01:13:30.560 And if you're familiar with like an old school typewriter or even a printer 01:13:30.560 --> 01:13:33.570 nowadays, it generally prints from top to bottom. 01:13:33.570 --> 01:13:38.550 So even if you have multiple columns, you print out one line at a time, 01:13:38.550 --> 01:13:41.360 and while you're on that line, the printer or the typewriter 01:13:41.360 --> 01:13:42.750 prints from left to right. 01:13:42.750 --> 01:13:46.550 And that's the mental model to have with your black and white terminal window. 01:13:46.550 --> 01:13:50.810 All of the output for every example thus far starts at the top 01:13:50.810 --> 01:13:52.340 and goes down to the bottom. 01:13:52.340 --> 01:13:54.120 From top to bottom, left to right. 01:13:54.120 --> 01:13:58.770 So we have to generate our output, our square in that same way. 01:13:58.770 --> 01:14:01.070 So let me propose that we do this. 01:14:01.070 --> 01:14:04.790 Let me propose that we know we need to iterate this many times, 3 or more 01:14:04.790 --> 01:14:05.810 generally size. 01:14:05.810 --> 01:14:06.560 So let me do this. 01:14:06.560 --> 01:14:12.200 For i in the range of size, what do I need to do three times? 01:14:12.200 --> 01:14:14.520 Well, I want to print out what? 01:14:14.520 --> 01:14:17.790 1, 2, 3 rows of bricks. 01:14:17.790 --> 01:14:20.850 But within each row of bricks, what do I want to print? 01:14:20.850 --> 01:14:24.220 1, 2, 3 bricks specifically. 01:14:24.220 --> 01:14:26.790 So if we go back to our diagram here and I 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, 01:14:33.700 --> 01:14:35.880 what did I want to do to print the first row? 01:14:35.880 --> 01:14:40.095 I want to print brick brick, brick. 01:14:40.095 --> 01:14:42.720 What do I want to print on the second row? brick, brick, brick. 01:14:42.720 --> 01:14:44.580 And the third row, brick, brick, brick. 01:14:44.580 --> 01:14:48.390 So I'm doing three things three times. 01:14:48.390 --> 01:14:50.650 There's a lot of printing that must happen. 01:14:50.650 --> 01:14:53.670 So let me go back to my code here and let me propose now 01:14:53.670 --> 01:14:57.540 that we think of this outer loop that I've just started 01:14:57.540 --> 01:15:00.960 as representing each of our rows. 01:15:00.960 --> 01:15:04.950 For i in range of size is going to ensure, no matter 01:15:04.950 --> 01:15:10.920 what I do next, that I can print out 1, 2, 3 rows, or more generally, 01:15:10.920 --> 01:15:15.030 size, where size could be 3, but it could be smaller or larger. 01:15:15.030 --> 01:15:17.520 What do I want to do on each of the rows? 01:15:17.520 --> 01:15:21.270 Well, just like an old school typewriter or printer, on each row, 01:15:21.270 --> 01:15:24.420 I want to print out brick, brick, brick; brick, brick, brick; brick, brick, 01:15:24.420 --> 01:15:25.470 brick. 01:15:25.470 --> 01:15:28.260 Well, that sounds like a cycle, some kind of loop. 01:15:28.260 --> 01:15:31.740 So maybe I can have inside of one loop another loop. 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 01:15:35.100 --> 01:15:36.450 and mess up my counting. 01:15:36.450 --> 01:15:38.860 So I'm going to by convention use j. 01:15:38.860 --> 01:15:41.460 Very common to use i and then j-- maybe k, 01:15:41.460 --> 01:15:44.800 but after that, you shouldn't keep nesting inside of each other. 01:15:44.800 --> 01:15:47.790 Let me go ahead and say for j in range of size 2, 01:15:47.790 --> 01:15:50.940 because it's a square, and then each of these rows, 01:15:50.940 --> 01:15:57.660 let me print out a single hash, but no new line, but after each row, 01:15:57.660 --> 01:16:00.750 let me print only a new line. 01:16:00.750 --> 01:16:03.720 So there's a lot going on here, especially if you've never 01:16:03.720 --> 01:16:08.220 touched Python, let alone loops, but notice what I've done here, too, 01:16:08.220 --> 01:16:10.800 and I'll add some comments for clarity. 01:16:10.800 --> 01:16:22.300 For each row in square, for each brick in row, print brick. 01:16:22.300 --> 01:16:25.330 And here is where comments, and more generally, 01:16:25.330 --> 01:16:28.990 pseudocode can really help explain to yourself and to others 01:16:28.990 --> 01:16:30.820 what your lines of code are doing. 01:16:30.820 --> 01:16:35.410 On line 8, I'm iterating from i equals 0 on up to size. 01:16:35.410 --> 01:16:37.180 So 0, 1, 2. 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. 01:16:41.560 --> 01:16:45.490 But that's good, because i represents how each of my rows. 01:16:45.490 --> 01:16:49.300 And while I'm on each of those rows, inside of this outer loop, 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. 01:16:53.110 --> 01:16:56.830 But I don't want my cursor to keep moving to the next line 01:16:56.830 --> 01:17:01.260 while I'm on a row, so I'm just overriding that line ending. 01:17:01.260 --> 01:17:03.010 But let me ask you a question of the group 01:17:03.010 --> 01:17:10.160 now, why on line 16 do I have a print here all by itself? 01:17:10.160 --> 01:17:13.820 Why do I have a print all by itself? 01:17:13.820 --> 01:17:19.180 Notice that it's below the inner loop, but inside 01:17:19.180 --> 01:17:22.300 of the outer loop, so to speak. 01:17:22.300 --> 01:17:26.650 What is that loop on line 16 doing ultimately? 01:17:26.650 --> 01:17:29.080 AUDIENCE: Every time you finish a line, you 01:17:29.080 --> 01:17:33.490 have to add a new line at the end of it. 01:17:33.490 --> 01:17:36.905 So print, it prints a new line. 01:17:36.905 --> 01:17:37.780 DAVID MALAN: Perfect. 01:17:37.780 --> 01:17:40.330 I don't want a new line after every brick. 01:17:40.330 --> 01:17:42.670 I only want to do that at the end of the row, 01:17:42.670 --> 01:17:45.460 and that's why my comments now are perhaps enlightening. 01:17:45.460 --> 01:17:51.460 Notice that this loop here is just iterating for each brick in the row. 01:17:51.460 --> 01:17:54.190 Once I'm done with that inner loop, so to speak, 01:17:54.190 --> 01:17:57.760 once I'm done with these highlighted lines here, to Evelyn's point, 01:17:57.760 --> 01:17:59.927 I need to print out one blank new line. 01:17:59.927 --> 01:18:03.010 And we've not done this before, but when you call print with no arguments, 01:18:03.010 --> 01:18:05.770 all you get is that automatic line ending, 01:18:05.770 --> 01:18:09.110 the backslash n where the cursor moves to the next line. 01:18:09.110 --> 01:18:13.540 So if I now go back to my terminal window and run mario.py, 01:18:13.540 --> 01:18:16.653 I think I should get a 3-by-3 square. 01:18:16.653 --> 01:18:18.820 And it doesn't quite look like a square on my screen 01:18:18.820 --> 01:18:22.300 because these hashes are a little taller than they are wide, but it is, in fact, 01:18:22.300 --> 01:18:23.680 3-by-3. 01:18:23.680 --> 01:18:26.140 But let me propose, as we've always done here, how 01:18:26.140 --> 01:18:28.030 we might tighten up this code further. 01:18:28.030 --> 01:18:32.050 Just for clarity's sake, let me get rid of my comments for a moment 01:18:32.050 --> 01:18:35.680 just so we can see how many lines of code we have total. 01:18:35.680 --> 01:18:39.040 And let me propose that we maybe do this. 01:18:39.040 --> 01:18:41.737 Let me propose that, you know what, this inner loop, 01:18:41.737 --> 01:18:43.570 especially if you're having trouble wrapping 01:18:43.570 --> 01:18:46.360 your mind around one loop inside of another loop, 01:18:46.360 --> 01:18:47.710 you don't strictly need it. 01:18:47.710 --> 01:18:49.270 What if we do this trick again? 01:18:49.270 --> 01:18:54.130 What if we print out inside of the outer and only loop each 01:18:54.130 --> 01:18:57.910 of those hashes times the number of times we want them? 01:18:57.910 --> 01:19:00.400 We draw inspiration from an earlier approach 01:19:00.400 --> 01:19:03.980 and we run Python now of mario.py, same result, 01:19:03.980 --> 01:19:07.480 but now, print square is really nice and compact. 01:19:07.480 --> 01:19:10.810 It has one explicit loop, and it's still printing out 01:19:10.810 --> 01:19:15.340 using string multiplication all of the hashes at once on that row. 01:19:15.340 --> 01:19:19.600 If you like abstraction and you'd like to wrap your mind more around what 01:19:19.600 --> 01:19:21.580 the code is doing, well, let's do this. 01:19:21.580 --> 01:19:23.770 If you're not quite clear on what's going on, 01:19:23.770 --> 01:19:25.870 let's propose that you implement a function called 01:19:25.870 --> 01:19:28.150 print row, passing in size. 01:19:28.150 --> 01:19:33.850 And let me propose that this print row function, it simply take in that width 01:19:33.850 --> 01:19:39.260 and print out the individual hash times that many times. 01:19:39.260 --> 01:19:43.870 In other words, here's an opportunity for abstraction, whereby, well, what 01:19:43.870 --> 01:19:45.157 does it mean to print a row? 01:19:45.157 --> 01:19:46.990 Well, when you're implementing print square, 01:19:46.990 --> 01:19:49.720 I don't really care what it means to print a row, 01:19:49.720 --> 01:19:53.440 I just need to know that someone's taking care of printing the row. 01:19:53.440 --> 01:19:56.740 You can pass the buck to another function altogether. 01:19:56.740 --> 01:19:58.360 And how does print row work? 01:19:58.360 --> 01:20:02.500 Well, it could use a for loop, it could use this string multiplication trick. 01:20:02.500 --> 01:20:05.980 This is a way to take a larger program-- and this is probably the most 01:20:05.980 --> 01:20:08.120 complicated one we've looked at thus far-- 01:20:08.120 --> 01:20:13.600 and to decompose it into these smaller components, that once assembled, 01:20:13.600 --> 01:20:16.390 achieve your final idea. 01:20:16.390 --> 01:20:19.780 Seeing no questions, that's the end of our look at loops 01:20:19.780 --> 01:20:22.900 in Python, this ability to do things cyclically again and again, 01:20:22.900 --> 01:20:25.480 and when we combine those with conditionals, this ability 01:20:25.480 --> 01:20:28.870 to ask and answer questions and combine them with our functions and variables, 01:20:28.870 --> 01:20:31.450 we really now have most of the building blocks 01:20:31.450 --> 01:20:34.060 we need to solve much larger, much more interesting, much 01:20:34.060 --> 01:20:35.260 more personal questions. 01:20:35.260 --> 01:20:39.100 So in the weeks to come, we'll start to see exactly what could go wrong, 01:20:39.100 --> 01:20:41.080 though, when we do so, but we'll introduce you 01:20:41.080 --> 01:20:45.600 to all the more tools via which you can troubleshoot those same problems.