WEBVTT X-TIMESTAMP-MAP=LOCAL:00:00:00.000,MPEGTS:900000 00:00:00.000 --> 00:00:02.946 [MUSIC PLAYING] 00:00:25.020 --> 00:00:28.560 DAVID MALAN: This is CS50's Introduction to Programming with Python. 00:00:28.560 --> 00:00:32.100 My name is David Malan, and this week we focus on conditionals. 00:00:32.100 --> 00:00:36.120 Conditionals, or conditional statements, in Python and in other languages, 00:00:36.120 --> 00:00:40.620 are this ability to ask questions and answer those questions, in order 00:00:40.620 --> 00:00:43.260 to decide do you want to execute this line of code? 00:00:43.260 --> 00:00:44.220 Or this line of code? 00:00:44.220 --> 00:00:46.020 Or this other line of code instead? 00:00:46.020 --> 00:00:48.780 They allow you to take the proverbial forks in the road, 00:00:48.780 --> 00:00:50.730 within your own code, logically. 00:00:50.730 --> 00:00:54.210 So how might we go about making some of these decisions? 00:00:54.210 --> 00:00:57.592 Well, it turns out that Python comes with a lot of built-in syntax. 00:00:57.592 --> 00:00:59.550 For instance, here are just some of the symbols 00:00:59.550 --> 00:01:01.770 you can use in Python to ask questions. 00:01:01.770 --> 00:01:04.860 Admittedly, mathematical questions, but we'll start there, if only 00:01:04.860 --> 00:01:07.470 to keep the examples simple early on. 00:01:07.470 --> 00:01:11.160 This first symbol, as you might know from math, represents greater than. 00:01:11.160 --> 00:01:14.640 The second symbol might not look too familiar, because we usually write it 00:01:14.640 --> 00:01:16.800 all as one thing on a piece of paper. 00:01:16.800 --> 00:01:19.830 But on a keyboard, if you want to say greater than or equal to, 00:01:19.830 --> 00:01:21.300 you'd use this symbol instead. 00:01:21.300 --> 00:01:22.920 This, of course, means less than. 00:01:22.920 --> 00:01:25.590 This means less than or equal to. 00:01:25.590 --> 00:01:27.720 And this one's a bit of a curiosity. 00:01:27.720 --> 00:01:30.240 We've seen, in our look at functions and variables, 00:01:30.240 --> 00:01:35.650 how we were able to assign values to variables using a single equal sign. 00:01:35.650 --> 00:01:38.010 But that equal sign didn't represent equality. 00:01:38.010 --> 00:01:40.230 It represented assignment, from right to left. 00:01:40.230 --> 00:01:42.390 That's great, because it solved that problem. 00:01:42.390 --> 00:01:45.030 But it left us in a bit of a bind, because how do we now 00:01:45.030 --> 00:01:47.190 compare two things, left and right? 00:01:47.190 --> 00:01:51.390 Well, in Python, and in many languages, you actually use two equal sides. 00:01:51.390 --> 00:01:55.200 So two equal signs represents equality, comparing the thing 00:01:55.200 --> 00:01:56.310 on the left and the right. 00:01:56.310 --> 00:01:59.250 One equal sign, as always, represents assignment, 00:01:59.250 --> 00:02:01.650 copying the thing from the right to the left. 00:02:01.650 --> 00:02:04.650 Lastly, this last symbol represents not equal to. 00:02:04.650 --> 00:02:08.699 So the exclamation point, or bang, followed by an equal sign, 00:02:08.699 --> 00:02:12.180 means not equal to some value next to it. 00:02:12.180 --> 00:02:15.900 Well, to ask the questions using these symbols, or any others, 00:02:15.900 --> 00:02:18.240 we're going to need another keyword in Python. 00:02:18.240 --> 00:02:21.120 And that keyword, quite simply, as in English, is if. 00:02:21.120 --> 00:02:24.420 You can ask questions in Python code along the lines of, 00:02:24.420 --> 00:02:28.890 if the answer to this question is true, then go ahead 00:02:28.890 --> 00:02:30.760 and execute this code for me. 00:02:30.760 --> 00:02:33.240 So let's go ahead and write some of these examples here. 00:02:33.240 --> 00:02:35.073 I'm going to go over to VS Code. 00:02:35.073 --> 00:02:36.990 And let's go ahead and create a program first, 00:02:36.990 --> 00:02:39.900 called compare.py, the goal of which is simply 00:02:39.900 --> 00:02:44.980 to write code that compares values and makes decisions based on those values. 00:02:44.980 --> 00:02:47.400 Let's go ahead and type code of compare.py, 00:02:47.400 --> 00:02:49.980 in order to create a brand new file called compare, 00:02:49.980 --> 00:02:52.415 in which we'll start to express some of this logic. 00:02:52.415 --> 00:02:53.790 Well, what do we want to compare? 00:02:53.790 --> 00:02:56.130 Suppose we want to compare, for the sake of discussion, 00:02:56.130 --> 00:02:57.540 just a couple of integers. 00:02:57.540 --> 00:03:00.210 But we'd like those integers to come from the user, 00:03:00.210 --> 00:03:03.810 so that we can make decisions based on numbers 00:03:03.810 --> 00:03:05.915 we don't know the values of in advance. 00:03:05.915 --> 00:03:07.290 Well, let's go ahead and do this. 00:03:07.290 --> 00:03:10.350 As we've done in the past, let's declare it a variable, like x. 00:03:10.350 --> 00:03:15.330 Let's assign it equal to the return value of the int function, 00:03:15.330 --> 00:03:19.320 and pass to the int function the return value of the input function, 00:03:19.320 --> 00:03:22.680 asking the user a question like, what's x, question 00:03:22.680 --> 00:03:24.210 mark, as we've done in the past. 00:03:24.210 --> 00:03:29.490 Let's do this one more time with y, asking the user for the value of y. 00:03:29.490 --> 00:03:33.790 And, again, converting that, ultimately, to an int, as well. 00:03:33.790 --> 00:03:37.200 So with this amount of the story, we have two variables, x and y, 00:03:37.200 --> 00:03:38.622 each of which has values. 00:03:38.622 --> 00:03:41.080 And ideally, we should be able to now compare these values. 00:03:41.080 --> 00:03:45.510 So suppose I want to make a decision based on the values of these variables. 00:03:45.510 --> 00:03:46.848 I'm going to use the keyword if. 00:03:46.848 --> 00:03:49.140 And I'm going to use some of those mathematical symbols 00:03:49.140 --> 00:03:51.100 to actually ask the question itself. 00:03:51.100 --> 00:03:55.860 So how about this, if x is less than y, then let's go ahead and just 00:03:55.860 --> 00:03:56.940 print as much out. 00:03:56.940 --> 00:03:59.700 Quote, unquote x is less than y. 00:03:59.700 --> 00:04:02.250 So this isn't a very interesting program yet. 00:04:02.250 --> 00:04:05.580 I'm literally just stating the obvious, based on the math. 00:04:05.580 --> 00:04:08.160 But it's allowing me to now introduce some new syntax. 00:04:08.160 --> 00:04:10.020 And exactly what is the syntax? 00:04:10.020 --> 00:04:12.990 Well, it's this-- not just the keyword if, which 00:04:12.990 --> 00:04:15.180 I've added here at the start of line four, 00:04:15.180 --> 00:04:18.450 but then I asked my question here, x less than y. 00:04:18.450 --> 00:04:21.450 x is one variable on the left, y is one variable on the right. 00:04:21.450 --> 00:04:24.570 And, of course, the less than sign is expressing the mathematical question 00:04:24.570 --> 00:04:25.200 I have. 00:04:25.200 --> 00:04:26.970 What I've highlighted here is technically 00:04:26.970 --> 00:04:29.400 called a Boolean expression. 00:04:29.400 --> 00:04:32.550 A Boolean expression, named after a mathematician named Bool, 00:04:32.550 --> 00:04:36.870 is simply a question that has a yes or no answer, or technically, 00:04:36.870 --> 00:04:38.760 a true or false answer. 00:04:38.760 --> 00:04:41.670 And that's nice because if there's only two possible answers, 00:04:41.670 --> 00:04:44.760 it's very easy for me, and in turn the computer, to make a decision-- 00:04:44.760 --> 00:04:47.100 do this, or don't do this thing. 00:04:47.100 --> 00:04:49.800 Now notice, if you come from other languages, 00:04:49.800 --> 00:04:53.100 you might notice that I have not typed any parentheses. 00:04:53.100 --> 00:04:56.190 They are not, in fact, necessary, at least in this case, in Python, 00:04:56.190 --> 00:04:58.980 but I have typed a colon at the end of the line. 00:04:58.980 --> 00:05:01.920 And even more importantly, at the next line 00:05:01.920 --> 00:05:04.350 I have begun my line with some indentation, 00:05:04.350 --> 00:05:07.380 hitting the space bar four times, or just hitting Tab once, 00:05:07.380 --> 00:05:09.660 which will automatically be converted to the same. 00:05:09.660 --> 00:05:13.980 That indentation is what tells Python that line five should only 00:05:13.980 --> 00:05:20.260 be executed if the answer to line four's question is, in fact, true. 00:05:20.260 --> 00:05:24.022 So if x is less than y, that phrase will be printed thereafter. 00:05:24.022 --> 00:05:25.730 Well, let's add a few more lines of code. 00:05:25.730 --> 00:05:26.855 How about another question? 00:05:26.855 --> 00:05:30.550 If x is greater than y, then let's go ahead and print that. 00:05:30.550 --> 00:05:33.010 x is greater than y. 00:05:33.010 --> 00:05:38.560 And let's do one final question, if x equals y, then-- wait a minute. 00:05:38.560 --> 00:05:41.360 What have I done wrong here? 00:05:41.360 --> 00:05:42.250 A good eye here. 00:05:42.250 --> 00:05:44.080 I don't want to assign y to x. 00:05:44.080 --> 00:05:48.430 If x equals equals y is how I express equality, let's go ahead 00:05:48.430 --> 00:05:52.420 and print out x is equal to y. 00:05:52.420 --> 00:05:56.470 So I now have three conditions, if you will, 00:05:56.470 --> 00:05:59.935 one question asking x less than y, one asking x greater than y, 00:05:59.935 --> 00:06:02.860 one asking x equals equals y. 00:06:02.860 --> 00:06:03.912 Let's run the code. 00:06:03.912 --> 00:06:05.620 Well, down here in my terminal window I'm 00:06:05.620 --> 00:06:08.320 going to run Python of compare.py and hit Enter. 00:06:08.320 --> 00:06:09.190 What's x? 00:06:09.190 --> 00:06:10.390 Let's go with one. 00:06:10.390 --> 00:06:11.140 What's y? 00:06:11.140 --> 00:06:12.370 Let's go with two. 00:06:12.370 --> 00:06:15.940 This should, of course, execute that first line of code 00:06:15.940 --> 00:06:18.970 and tell me, indeed, that x is less than y. 00:06:18.970 --> 00:06:21.670 Exactly as I would expect there. 00:06:21.670 --> 00:06:24.400 Well, what just happened, though, in code? 00:06:24.400 --> 00:06:28.090 Well, let's take a look, perhaps, at this same code visually, 00:06:28.090 --> 00:06:31.210 particularly if you're a more visual learner, this, I dare say, 00:06:31.210 --> 00:06:32.500 is what just happened. 00:06:32.500 --> 00:06:34.840 So what we're looking at here is a flow chart. 00:06:34.840 --> 00:06:37.900 It's a diagram of this program's logic. 00:06:37.900 --> 00:06:41.470 And more technically, it shows the program's control flow. 00:06:41.470 --> 00:06:43.510 That is, the ability of you, in code, to control 00:06:43.510 --> 00:06:46.210 the flow of a program, generally from top to bottom. 00:06:46.210 --> 00:06:49.300 In fact, let me go ahead and zoom in on the top of this flow chart. 00:06:49.300 --> 00:06:52.510 And you'll see an oval at the very top that says, quite literally, start. 00:06:52.510 --> 00:06:55.450 That is, irrespective of what shape or layout 00:06:55.450 --> 00:06:58.180 the diagram is, where your own thinking and logic 00:06:58.180 --> 00:07:01.460 should start when trying to wrap your mind around this program. 00:07:01.460 --> 00:07:04.480 Notice that there's an arrow from start to this diamond shape. 00:07:04.480 --> 00:07:07.450 And inside of that diamond is a question, a Boolean expression, 00:07:07.450 --> 00:07:08.800 x less than y. 00:07:08.800 --> 00:07:12.190 And this shape just means, based on the answer to that question, 00:07:12.190 --> 00:07:14.140 go left or go right. 00:07:14.140 --> 00:07:16.690 Specifically, go left if the answer is true, 00:07:16.690 --> 00:07:19.240 or go right if the answer is false. 00:07:19.240 --> 00:07:24.460 Well, the inputs I typed were one and two, respectively, for x and y. 00:07:24.460 --> 00:07:26.980 So, of course, one is less than two. 00:07:26.980 --> 00:07:32.530 So that's why my program printed out, quote unquote, x is less than y. 00:07:32.530 --> 00:07:34.120 But recall the code. 00:07:34.120 --> 00:07:37.270 The code then proceeded to ask two more questions. 00:07:37.270 --> 00:07:38.800 Is x greater than y? 00:07:38.800 --> 00:07:40.570 Is x equal equal to y? 00:07:40.570 --> 00:07:43.570 Well, the flow chart depicts those questions, too. 00:07:43.570 --> 00:07:46.090 Notice that no matter whether the question 00:07:46.090 --> 00:07:50.530 had an answer of true or false, the arrows both converge back down 00:07:50.530 --> 00:07:52.990 to this second diamond shape here. 00:07:52.990 --> 00:07:57.070 And that second diamond shape asks the second question, x greater than y. 00:07:57.070 --> 00:07:58.840 That, too, has a true or false answer. 00:07:58.840 --> 00:08:00.560 So we go one way or the other. 00:08:00.560 --> 00:08:04.600 But if x is one and y is two, then no, the answer is false. 00:08:04.600 --> 00:08:06.190 One is not greater than y. 00:08:06.190 --> 00:08:09.430 So logically, in the flow chart, you follow the false arrow this time. 00:08:09.430 --> 00:08:13.750 And notice, along that false arrow you don't print anything this time. 00:08:13.750 --> 00:08:16.067 That's why we only saw one printout on the screen. 00:08:16.067 --> 00:08:17.650 Now, there was still a third question. 00:08:17.650 --> 00:08:19.442 And this flow chart captures that, as well. 00:08:19.442 --> 00:08:22.480 The third diamond asks x equals equals y. 00:08:22.480 --> 00:08:25.720 Now that, too, has a false answer in this case, because one, of course, 00:08:25.720 --> 00:08:27.250 does not equal equal y. 00:08:27.250 --> 00:08:30.830 And so we again follow the third false branch here. 00:08:30.830 --> 00:08:32.890 And that leads us, of course, to stop. 00:08:32.890 --> 00:08:35.659 And stop just indicates that's it for the program. 00:08:35.659 --> 00:08:38.020 So I think that's correct. 00:08:38.020 --> 00:08:40.780 And that particular flow chart does happen 00:08:40.780 --> 00:08:44.140 to represent the actual code that I wrote. 00:08:44.140 --> 00:08:45.220 So it's correct. 00:08:45.220 --> 00:08:46.690 It does what it's supposed to do. 00:08:46.690 --> 00:08:50.290 It answered the question correctly by printing on the screen x less than y. 00:08:50.290 --> 00:08:53.803 But what is, perhaps, poorly designed about it? 00:08:53.803 --> 00:08:55.220 Let's make this first distinction. 00:08:55.220 --> 00:08:56.770 It's not enough, necessarily, for the code 00:08:56.770 --> 00:08:58.937 that you write to be correct and do what you intend. 00:08:58.937 --> 00:09:02.270 Longer term, especially as our programs get longer and more sophisticated, 00:09:02.270 --> 00:09:06.910 more complicated, we're going to want them to be well-designed, too. 00:09:06.910 --> 00:09:12.610 Thoughts on in what way this program is arguably not well designed, 00:09:12.610 --> 00:09:15.230 even though it's correct? 00:09:15.230 --> 00:09:16.300 Let's see here. 00:09:16.300 --> 00:09:18.880 Khalid, if I'm saying that right, your thoughts? 00:09:18.880 --> 00:09:21.730 KHALID: Too many ifs, I think, is getting repetitive. 00:09:21.730 --> 00:09:23.930 We can make our code more concise, maybe. 00:09:23.930 --> 00:09:25.930 DAVID MALAN: Yeah, it seems a little repetitive. 00:09:25.930 --> 00:09:28.692 I'm asking if this, if this, if this. 00:09:28.692 --> 00:09:31.900 And yet, logically, I should know the answer to some of those later questions 00:09:31.900 --> 00:09:33.040 once I figure one out. 00:09:33.040 --> 00:09:35.350 And, in short, if you look at this diagram here, 00:09:35.350 --> 00:09:38.650 notice that no matter whether I go left or I go right, 00:09:38.650 --> 00:09:41.110 I'm always asking three questions. 00:09:41.110 --> 00:09:45.230 No matter what, all of those arrows lead to the first, the second, 00:09:45.230 --> 00:09:46.480 and the third diamond. 00:09:46.480 --> 00:09:49.810 So I'm asking three questions, no matter whether any of those answers 00:09:49.810 --> 00:09:50.862 are true or false. 00:09:50.862 --> 00:09:52.570 Well how might I go about improving this? 00:09:52.570 --> 00:09:55.240 Well, let me propose that we introduce another keyword 00:09:55.240 --> 00:09:57.760 to our Python vocabulary, namely elif. 00:09:57.760 --> 00:09:59.830 And this, too, is kind of a succinct one. 00:09:59.830 --> 00:10:02.770 It's a conjunction of else if, in English, 00:10:02.770 --> 00:10:07.960 which allows us to ask a question that takes into account whether or not 00:10:07.960 --> 00:10:10.840 a previous question had a true or false answer. 00:10:10.840 --> 00:10:12.110 Well, what do I mean by that? 00:10:12.110 --> 00:10:13.810 Well, let me go back to my code here. 00:10:13.810 --> 00:10:17.830 And let me propose that we now improve upon this, here, 00:10:17.830 --> 00:10:22.360 by asking ourselves, ultimately, how can we ask fewer questions? 00:10:22.360 --> 00:10:24.460 And let me go ahead here and propose that 00:10:24.460 --> 00:10:30.700 instead of asking if, if, if, let's make these conditions potentially mutually 00:10:30.700 --> 00:10:31.700 exclusive. 00:10:31.700 --> 00:10:35.920 That is to say, don't keep answering questions once we get back 00:10:35.920 --> 00:10:37.220 a true answer. 00:10:37.220 --> 00:10:39.440 So I'm going to change my code up here as follows. 00:10:39.440 --> 00:10:45.160 Instead of asking if, if, if, I'm going to say, if x less than y, elif x 00:10:45.160 --> 00:10:50.140 greater than y, elif x equals equals y. 00:10:50.140 --> 00:10:52.780 So I'm going to implicitly, just like an English, 00:10:52.780 --> 00:10:57.520 take into account that I'm only going to keep asking myself these questions 00:10:57.520 --> 00:11:00.340 if I haven't yet gotten a true response. 00:11:00.340 --> 00:11:02.080 Think about the logic here, the English. 00:11:02.080 --> 00:11:07.660 If x is less than y, on line four, print out x is less than y. 00:11:07.660 --> 00:11:10.300 Well, if that's the case, you're done, logically. 00:11:10.300 --> 00:11:15.670 Because if the English is saying if x less than y, else if x greater than y, 00:11:15.670 --> 00:11:19.030 those are going to be mutually exclusive if the answer to the first question 00:11:19.030 --> 00:11:19.625 is true. 00:11:19.625 --> 00:11:22.750 You don't have to keep asking questions to which you already logically know 00:11:22.750 --> 00:11:23.570 the answer. 00:11:23.570 --> 00:11:25.418 So let me go ahead now and run this program. 00:11:25.418 --> 00:11:27.460 And I think the behavior is going to be the same. 00:11:27.460 --> 00:11:29.710 Python of compare.py, what's x? 00:11:29.710 --> 00:11:30.550 Let's do one. 00:11:30.550 --> 00:11:31.210 What's y? 00:11:31.210 --> 00:11:32.400 Let's do two. 00:11:32.400 --> 00:11:33.910 x is less than y. 00:11:33.910 --> 00:11:37.330 Now, honestly, I didn't really notice a difference when I ran the program. 00:11:37.330 --> 00:11:41.020 And honestly, my Mac, my PC, my phone nowadays, 00:11:41.020 --> 00:11:44.020 are so darn fast that these kinds of improvements 00:11:44.020 --> 00:11:47.110 aren't going to necessarily feel any faster until we're 00:11:47.110 --> 00:11:49.300 writing bigger, faster programs. 00:11:49.300 --> 00:11:52.640 But it's laying the foundation for writing better code longer term. 00:11:52.640 --> 00:11:54.640 Now what is the improvement I've just made? 00:11:54.640 --> 00:11:57.650 Well, if previously my diagram looked like this, 00:11:57.650 --> 00:12:02.740 which was problematic insofar as I was asking three questions no matter 00:12:02.740 --> 00:12:06.280 what, even if I already figured out what I want to print on the screen. 00:12:06.280 --> 00:12:10.720 This new version of the program that says if, elif, elif, might look 00:12:10.720 --> 00:12:12.460 a little something like this instead. 00:12:12.460 --> 00:12:13.630 Now it got a little wider. 00:12:13.630 --> 00:12:16.390 That's just because we drew the arrows to be a bit wider here. 00:12:16.390 --> 00:12:19.030 But let's focus on just how many questions are getting asked. 00:12:19.030 --> 00:12:20.950 Let me zoom in at the top, as before. 00:12:20.950 --> 00:12:25.030 And let me propose that we note that the start oval is at the very top, 00:12:25.030 --> 00:12:27.400 and it's asking us to ask one question first. 00:12:27.400 --> 00:12:29.980 x less than y, is one less than two? 00:12:29.980 --> 00:12:33.400 But notice here, let me zoom out, if one is, indeed, less 00:12:33.400 --> 00:12:39.550 than two, we follow this longer arrow down, marked true. 00:12:39.550 --> 00:12:42.580 We print out quote, unquote x is less than y. 00:12:42.580 --> 00:12:48.160 But then we immediately follow this next arrow down to the icon that says stop. 00:12:48.160 --> 00:12:51.670 So that's what's implied by doing if, elif, elif. 00:12:51.670 --> 00:12:55.210 If we get back a true answer right away to that first if, 00:12:55.210 --> 00:12:57.700 we're going to print out x is less than y and then stop. 00:12:57.700 --> 00:12:59.870 We're logically at the end of the program. 00:12:59.870 --> 00:13:03.190 So this picture is just representing, graphically, 00:13:03.190 --> 00:13:05.650 what the code is actually doing. 00:13:05.650 --> 00:13:07.330 But suppose I typed in something else. 00:13:07.330 --> 00:13:13.450 Suppose that my code actually ran, and I typed in two for x and one for y. 00:13:13.450 --> 00:13:16.430 That is to say, the answer to the first question is now false. 00:13:16.430 --> 00:13:19.000 But the answer to the second question is now true. 00:13:19.000 --> 00:13:23.340 Because, of course, two is greater than one. 00:13:23.340 --> 00:13:25.240 Well, let's go back to the diagram. 00:13:25.240 --> 00:13:28.570 Same as before, we start at the very top where it says start. 00:13:28.570 --> 00:13:33.520 The very first question up here, now, x less than y, is an answer of false, 00:13:33.520 --> 00:13:35.950 because no, two is not less than one. 00:13:35.950 --> 00:13:39.190 So we follow this arrow to the next question, this diamond. 00:13:39.190 --> 00:13:40.840 Is x greater than y? 00:13:40.840 --> 00:13:43.660 Well, yes, two is greater than one. 00:13:43.660 --> 00:13:47.510 So now we follow this left arrow, which is true. 00:13:47.510 --> 00:13:52.250 We print out quote, unquote x is greater than y, and then stop. 00:13:52.250 --> 00:13:53.530 So what's the improvement? 00:13:53.530 --> 00:13:55.810 Well, in the first case, we got lucky and we only 00:13:55.810 --> 00:13:58.090 had to ask one question and boom, we're done. 00:13:58.090 --> 00:14:01.420 This time, we had to ask two questions, but then boom, we're done. 00:14:01.420 --> 00:14:07.390 Only if x happens to equal y do we actually find ourselves, logically, 00:14:07.390 --> 00:14:11.620 getting all the way down to this final elif in my code. 00:14:11.620 --> 00:14:14.830 And pictorially, only if x is equal to y do 00:14:14.830 --> 00:14:17.980 we find ourselves going all the way down to the third diamond, 00:14:17.980 --> 00:14:23.020 the third question, asking is it equal to y or not? 00:14:23.020 --> 00:14:25.850 Now, hopefully, the answer at that point is not false. 00:14:25.850 --> 00:14:28.953 We've included a false arrow just so that the program itself 00:14:28.953 --> 00:14:29.620 is well-defined. 00:14:29.620 --> 00:14:33.520 But, logically, we shouldn't actually be getting there anyway, 00:14:33.520 --> 00:14:37.242 because it's got to be less than, or greater than, or equal to in this case. 00:14:37.242 --> 00:14:38.950 Well, let me pause here to see if there's 00:14:38.950 --> 00:14:42.340 any questions, now, either on the code version thereof here, 00:14:42.340 --> 00:14:47.090 or on this diagramming of that very same logic. 00:14:47.090 --> 00:14:52.130 Questions here, on this control flow? 00:14:52.130 --> 00:14:55.872 SPEAKER 1: Aren't we supposed to put an else at the end? 00:14:55.872 --> 00:14:57.080 DAVID MALAN: A good question. 00:14:57.080 --> 00:15:00.103 And yes-- so that's going to be my third and final approach. 00:15:00.103 --> 00:15:02.270 And if you don't mind, let's pivot there right away. 00:15:02.270 --> 00:15:04.820 Identifying a third keyword, that indeed exists 00:15:04.820 --> 00:15:09.020 in Python, that allows us to be even better at expressing this logic 00:15:09.020 --> 00:15:10.950 to design this program even better. 00:15:10.950 --> 00:15:13.560 And that's going to solve a particular problem. 00:15:13.560 --> 00:15:16.820 So if I take us back to our code here, notice 00:15:16.820 --> 00:15:20.750 that what I've highlighted earlier, elif x equals equals y. 00:15:20.750 --> 00:15:23.180 It's not wrong to ask that question. 00:15:23.180 --> 00:15:25.730 In fact, if you're trying to be especially thorough, 00:15:25.730 --> 00:15:29.660 it makes perfect sense to check if x is less than y, greater than y, 00:15:29.660 --> 00:15:31.010 or equal to y. 00:15:31.010 --> 00:15:37.280 But why don't I need to ask this third and final question? 00:15:37.280 --> 00:15:42.080 SPEAKER 2: We don't need to ask if x is equal to y any more because, logically, 00:15:42.080 --> 00:15:45.320 if the two conditionals evaluate to false, 00:15:45.320 --> 00:15:50.250 there is only one conditional that will evaluate to true. 00:15:50.250 --> 00:15:51.885 And that is x is equal to y. 00:15:51.885 --> 00:15:52.760 DAVID MALAN: Exactly. 00:15:52.760 --> 00:15:55.250 If we're all pretty comfortable with math, and comparisons 00:15:55.250 --> 00:15:58.820 here, of course x is either going to be less than y, greater than y, 00:15:58.820 --> 00:15:59.750 or equal to y. 00:15:59.750 --> 00:16:02.150 But once you rule out the first two scenarios, 00:16:02.150 --> 00:16:05.270 logically, it's got to be the case that x must equal y. 00:16:05.270 --> 00:16:08.060 If it wasn't the case, then it's less than or greater than. 00:16:08.060 --> 00:16:11.220 So Hope proposed that we use this other keyword, else. 00:16:11.220 --> 00:16:12.210 And how do we use this? 00:16:12.210 --> 00:16:13.752 Well, exactly as we might in English. 00:16:13.752 --> 00:16:15.110 Let me go back to my code here. 00:16:15.110 --> 00:16:18.830 And instead of bothering to ask the third and final question, 00:16:18.830 --> 00:16:20.330 let's not ask a question at all. 00:16:20.330 --> 00:16:24.630 Let's just have this catch-all. so to speak, a final line of code that says, 00:16:24.630 --> 00:16:27.830 else just assume that x is equal to y. 00:16:27.830 --> 00:16:29.682 Therefore, printing it as well. 00:16:29.682 --> 00:16:30.890 So what's the upside of that? 00:16:30.890 --> 00:16:33.570 My code is still going to work exactly the same. 00:16:33.570 --> 00:16:35.690 And again, my computer is so darn fast, I 00:16:35.690 --> 00:16:39.480 don't even notice that it's working even faster than it was before. 00:16:39.480 --> 00:16:41.210 But we would notice these kinds of things 00:16:41.210 --> 00:16:44.210 if we were doing a lot more work, a lot bigger programs here. 00:16:44.210 --> 00:16:46.400 But let me run Python of compare.py. 00:16:46.400 --> 00:16:49.670 Let's do, for instance, one and two. 00:16:49.670 --> 00:16:50.720 Still works for that. 00:16:50.720 --> 00:16:52.460 Let's do two and one. 00:16:52.460 --> 00:16:53.630 Still works for that. 00:16:53.630 --> 00:16:55.340 Let's do one and one. 00:16:55.340 --> 00:16:57.540 And it, indeed, now works for that. 00:16:57.540 --> 00:17:01.370 But in these cases now, let's consider the path we just went down. 00:17:01.370 --> 00:17:05.900 Previously, our diagram, when we had if, elif, elif in place, 00:17:05.900 --> 00:17:07.920 looked a little something like this. 00:17:07.920 --> 00:17:11.990 And notice, they began, we might have asked one question, or two, 00:17:11.990 --> 00:17:13.910 or worst case, three whole questions. 00:17:13.910 --> 00:17:17.329 But we can do better than that, using else, as Hope proposed, 00:17:17.329 --> 00:17:19.582 we can whittle this diagram, now, down to this. 00:17:19.582 --> 00:17:22.040 And even though it looks like the diagram's getting bigger, 00:17:22.040 --> 00:17:25.730 notice that it's having fewer building blocks inside of it. 00:17:25.730 --> 00:17:29.240 There's fewer arrows and there's fewer nodes in this picture. 00:17:29.240 --> 00:17:30.620 Let's start at the top now. 00:17:30.620 --> 00:17:34.160 Start leads us to the first question, still. x less than y? 00:17:34.160 --> 00:17:35.600 If the answer is true, great. 00:17:35.600 --> 00:17:38.420 We can say as much, x is less than y, and we can stop. 00:17:38.420 --> 00:17:41.450 If it's not true, if it's false, we can ask the next question. 00:17:41.450 --> 00:17:43.820 x is greater than y, true or false? 00:17:43.820 --> 00:17:44.840 If it is, great. 00:17:44.840 --> 00:17:47.270 We can print x is greater than y, and stop. 00:17:47.270 --> 00:17:51.510 Else, if it's not the case that x is greater than y, the answer is false. 00:17:51.510 --> 00:17:56.060 We can just immediately, logically, say x is equal to y. 00:17:56.060 --> 00:17:58.610 We don't have to add the third question at all. 00:17:58.610 --> 00:18:00.740 We can just immediately conclude there. 00:18:00.740 --> 00:18:02.150 So what's the implication here? 00:18:02.150 --> 00:18:05.180 You can see, with these pictures, a relative decrease 00:18:05.180 --> 00:18:07.140 in the complexity of a program. 00:18:07.140 --> 00:18:10.670 The first one was very long and stringy, with lots and lots of questions, 00:18:10.670 --> 00:18:12.283 unnecessarily, ultimately. 00:18:12.283 --> 00:18:13.700 The next one got a little shorter. 00:18:13.700 --> 00:18:15.560 And this one's even shorter still. 00:18:15.560 --> 00:18:19.280 And again, the fewer lines of code you have, the less likely 00:18:19.280 --> 00:18:21.400 you are, arguably, to make any mistakes. 00:18:21.400 --> 00:18:23.150 The easier it is for other people to read. 00:18:23.150 --> 00:18:26.930 And so, generally, this readability, this simplification, 00:18:26.930 --> 00:18:28.760 is, indeed, a good thing. 00:18:28.760 --> 00:18:33.200 Well, let's go ahead and add another piece of capability to Python, 00:18:33.200 --> 00:18:34.400 and that's this one here. 00:18:34.400 --> 00:18:37.730 Just like in English, where you can ask this question or this other question, 00:18:37.730 --> 00:18:41.540 you can say the same thing in Python using literally this word or. 00:18:41.540 --> 00:18:44.540 So let me go back to my Python code here. 00:18:44.540 --> 00:18:47.150 And let's propose how we might ask a couple of questions 00:18:47.150 --> 00:18:51.860 at once this time, perhaps this time considering how we might ask not 00:18:51.860 --> 00:18:54.050 whether or not it's greater than or equal to, 00:18:54.050 --> 00:18:56.070 and caring about the precise answer. 00:18:56.070 --> 00:18:58.190 Let's take a coarser approach here. 00:18:58.190 --> 00:19:04.730 And let's just try to determine is x equal to y or not? 00:19:04.730 --> 00:19:06.980 Well, let me go ahead and delete some of this code 00:19:06.980 --> 00:19:08.540 and change the question we're asking. 00:19:08.540 --> 00:19:12.290 Let me do this-- well, if I care about whether it's equal or not, 00:19:12.290 --> 00:19:14.060 let's check the possible scenarios. 00:19:14.060 --> 00:19:19.850 If x is less than y or x is greater than y, let's go ahead 00:19:19.850 --> 00:19:23.840 and print out x is not equal to y. 00:19:23.840 --> 00:19:26.240 Now why is that, no pun intended? 00:19:26.240 --> 00:19:29.240 If x is less than y, well, it's obviously not equal. 00:19:29.240 --> 00:19:31.730 If x is greater than y, it's obviously not equal. 00:19:31.730 --> 00:19:35.840 So we can conclude x is not equal to y. 00:19:35.840 --> 00:19:41.180 So if we, instead, want to make sure that it is equal to, 00:19:41.180 --> 00:19:47.940 we can just use Hope's else, using print quote, unquote x is equal to y. 00:19:47.940 --> 00:19:49.410 And again, why is this? 00:19:49.410 --> 00:19:52.470 Well, if x is less than y, or x is greater than y, 00:19:52.470 --> 00:19:53.820 they're obviously not equal. 00:19:53.820 --> 00:19:56.580 Otherwise, logically, they must be equal, in fact. 00:19:56.580 --> 00:19:57.390 So let's run this. 00:19:57.390 --> 00:19:59.565 Let's go ahead and run Python of compare.py. 00:19:59.565 --> 00:20:00.240 What's x? 00:20:00.240 --> 00:20:00.930 One. 00:20:00.930 --> 00:20:01.560 What's y? 00:20:01.560 --> 00:20:02.250 Two. 00:20:02.250 --> 00:20:03.960 OK, x is not equal to y. 00:20:03.960 --> 00:20:08.550 Let's do it again, put two for x, one for y. x is not equal to y. 00:20:08.550 --> 00:20:12.450 And one third time, how about x is one and y is one. 00:20:12.450 --> 00:20:14.760 x is now equal to y. 00:20:14.760 --> 00:20:17.610 Now if we want to compare that visually, too, 00:20:17.610 --> 00:20:20.980 let me propose that the picture looks a little something like this. 00:20:20.980 --> 00:20:23.340 And again, this is the exact same thing logically, 00:20:23.340 --> 00:20:25.197 but it's a pictorial representation thereof. 00:20:25.197 --> 00:20:26.280 What's the first question? 00:20:26.280 --> 00:20:30.900 Well, if x is less than y, well, then we follow the true arrow. 00:20:30.900 --> 00:20:33.840 And we say quote, unquote x is not equal to y. 00:20:33.840 --> 00:20:35.280 And then we stop. 00:20:35.280 --> 00:20:37.623 But what if x is not less than y? 00:20:37.623 --> 00:20:38.790 What if it's greater than y? 00:20:38.790 --> 00:20:40.800 What if it's two and one, respectively? 00:20:40.800 --> 00:20:44.590 Then the answer to x less than y, first question, is false. 00:20:44.590 --> 00:20:45.480 So we go here. 00:20:45.480 --> 00:20:48.720 We ask the second question, because of the or, 00:20:48.720 --> 00:20:51.060 and that asks is x greater than y? 00:20:51.060 --> 00:20:55.830 If so, notice this, we can kind of reuse some of the same parts of this picture, 00:20:55.830 --> 00:20:58.260 and just say x is not equal to y. 00:20:58.260 --> 00:21:01.020 We don't need to add arrows and ad boxes unnecessarily. 00:21:01.020 --> 00:21:06.480 We can reuse lines of code, parts of the picture, just as we have lines of code. 00:21:06.480 --> 00:21:07.620 And then we stop. 00:21:07.620 --> 00:21:09.780 Lastly, we have the following. 00:21:09.780 --> 00:21:12.300 If we know that x is not less than y, we know 00:21:12.300 --> 00:21:16.080 that x is not greater than y, it must be the case that x equals y. 00:21:16.080 --> 00:21:18.900 We don't need to ask a third question, another diamond. 00:21:18.900 --> 00:21:24.000 We can just immediately print as much, and then say stop, as well. 00:21:24.000 --> 00:21:25.710 Well, what could I do here? 00:21:25.710 --> 00:21:28.560 I bet I could improve this code slightly. 00:21:28.560 --> 00:21:31.440 And if we really want to be nitpicky, I would 00:21:31.440 --> 00:21:34.800 argue that this is now really just a minor refinement, 00:21:34.800 --> 00:21:37.410 but it's a good habit to get into thinking about. 00:21:37.410 --> 00:21:38.760 Could my code be better? 00:21:38.760 --> 00:21:41.100 Could my code be simpler? 00:21:41.100 --> 00:21:43.740 Could I improve this code further? 00:21:43.740 --> 00:21:47.160 It's subtle, but could I improve the design? 00:21:47.160 --> 00:21:48.960 Could I ask fewer questions? 00:21:48.960 --> 00:21:52.460 Could I tighten it up, so to speak? 00:21:52.460 --> 00:21:54.280 What do folks think? 00:21:54.280 --> 00:21:58.060 SPEAKER 3: You can ask is x is just equal to y. 00:21:58.060 --> 00:22:03.625 Then if you print x is equal to y, else x is not equal to y. 00:22:03.625 --> 00:22:04.500 DAVID MALAN: Perfect. 00:22:04.500 --> 00:22:07.560 Recall one of the other symbols we saw on the available list earlier. 00:22:07.560 --> 00:22:10.680 We can check not just less than, or greater than, or equal to. 00:22:10.680 --> 00:22:13.410 We can literally ask the question is it not equal to? 00:22:13.410 --> 00:22:17.400 Why are we wasting time asking if it's less than or if it's greater than? 00:22:17.400 --> 00:22:21.100 Well, if all you care about is is it not equal, I think we can do exactly that. 00:22:21.100 --> 00:22:24.610 Let's just ask the one simple question we do care about. 00:22:24.610 --> 00:22:25.950 And so let me go back up here. 00:22:25.950 --> 00:22:29.580 And let me just say not both of these questions, let's get rid of the or. 00:22:29.580 --> 00:22:33.840 Let's just say if x is not equal to y, then go 00:22:33.840 --> 00:22:36.510 ahead and print x is not equal to y. 00:22:36.510 --> 00:22:39.190 And that, too, I think is going to work exactly the same. 00:22:39.190 --> 00:22:41.980 But the picture now looks a little bit different. 00:22:41.980 --> 00:22:44.190 Notice that this was our flow chart earlier, 00:22:44.190 --> 00:22:45.947 that represented that same logic. 00:22:45.947 --> 00:22:47.280 And there's a bit of complexity. 00:22:47.280 --> 00:22:48.690 You've got to go left, you've got to go right, 00:22:48.690 --> 00:22:50.732 based on the answer to these couple of questions. 00:22:50.732 --> 00:22:53.820 If we now take into account what this version of the program looks like, 00:22:53.820 --> 00:22:56.820 it's even simpler, perhaps the simplest one we've seen yet. 00:22:56.820 --> 00:23:00.330 When we start off the program, we ask just one, and only one, question, 00:23:00.330 --> 00:23:02.040 is x not equal to y? 00:23:02.040 --> 00:23:06.930 And if so, true, we go ahead and print out x not equal to y. 00:23:06.930 --> 00:23:10.350 If the answer is false, then, of course, it must be equal to y, 00:23:10.350 --> 00:23:12.040 so we say that instead. 00:23:12.040 --> 00:23:14.070 And if we really want, we could invert this. 00:23:14.070 --> 00:23:17.080 If I go back here to my code, and if, for whatever reason, 00:23:17.080 --> 00:23:20.730 you just prefer to think in terms of equal or not equal, 00:23:20.730 --> 00:23:25.270 as opposed to not equal or equal, it's really up to you. 00:23:25.270 --> 00:23:27.900 We could change this to be equals equals. 00:23:27.900 --> 00:23:32.020 But I'm going to have to change my print statements to be in the opposite order. 00:23:32.020 --> 00:23:34.890 So let me go ahead, now, and reverse these two here, 00:23:34.890 --> 00:23:38.950 and move the second one first and the first one second. 00:23:38.950 --> 00:23:42.240 So now, when I execute this code, I'm asking still just one question. 00:23:42.240 --> 00:23:44.550 So it's still just as good, just as succinct. 00:23:44.550 --> 00:23:47.070 But now the diagram, instead of looking like this, 00:23:47.070 --> 00:23:50.310 is going to change the not equal to equal equal. 00:23:50.310 --> 00:23:54.400 And we just need to make sure that we print out the right thing, accordingly. 00:23:54.400 --> 00:23:57.990 And again, here too, just as the code is getting a little more compact, a little 00:23:57.990 --> 00:24:00.330 more compact, with fewer and fewer characters, 00:24:00.330 --> 00:24:05.460 so are these diagrams, these flow charts capturing the relative simplification 00:24:05.460 --> 00:24:08.040 of each of those programs, too. 00:24:08.040 --> 00:24:11.610 Let me go ahead and pause here to see if there's any questions, now, on any 00:24:11.610 --> 00:24:13.140 of these versions of code. 00:24:16.530 --> 00:24:19.150 SPEAKER 4: Yeah, I have a couple of questions. 00:24:19.150 --> 00:24:22.380 What if indentation is not used? 00:24:22.380 --> 00:24:25.600 DAVID MALAN: If indentation is not used, your program will not work. 00:24:25.600 --> 00:24:28.080 So Python is a little different from a lot 00:24:28.080 --> 00:24:32.100 of languages in that it enforces the indentation requirement. 00:24:32.100 --> 00:24:34.080 Some of you who have been programming for years 00:24:34.080 --> 00:24:37.800 might not necessarily be in the best habit of indenting your code properly. 00:24:37.800 --> 00:24:40.170 And one of the features, arguably, of Python 00:24:40.170 --> 00:24:44.850 is that it makes you indent your code, or it will not just work. 00:24:44.850 --> 00:24:47.460 And I think, did you have one other question? 00:24:47.460 --> 00:24:50.820 SPEAKER 4: Yeah, is the colon necessary? 00:24:50.820 --> 00:24:52.530 DAVID MALAN: Is the colon necessary? 00:24:52.530 --> 00:24:55.150 Yes, the colon, too, is necessary. 00:24:55.150 --> 00:24:57.960 So with Python, what you see is what you get here. 00:24:57.960 --> 00:25:01.020 And, indeed, it needs to be indented and the colon is necessary. 00:25:01.020 --> 00:25:05.670 Python does not use, in the same way by convention as C, and C++, and Java, 00:25:05.670 --> 00:25:07.410 curly braces to connote blocks. 00:25:07.410 --> 00:25:10.680 Instead, it relies, indeed, on this indentation. 00:25:10.680 --> 00:25:14.490 Well, let me propose that we introduce one other keyword here in Python, 00:25:14.490 --> 00:25:17.310 to see exactly how we might combine additional thoughts. 00:25:17.310 --> 00:25:20.490 And that's going to be literally the word and, a conjunction of one, 00:25:20.490 --> 00:25:24.690 or two, or more questions that we might want to ask at once. 00:25:24.690 --> 00:25:28.650 And let me propose, here, that we explore this kind of logic 00:25:28.650 --> 00:25:32.400 by way of another program altogether, in VS Code, whereby I'll go ahead now 00:25:32.400 --> 00:25:35.760 and create a new program, say, called grade.py. 00:25:35.760 --> 00:25:38.160 Let's consider exactly what grade a student should get, 00:25:38.160 --> 00:25:40.950 based on their score on an exam, or a test, or a quiz, 00:25:40.950 --> 00:25:42.900 or some other assignment like that. 00:25:42.900 --> 00:25:46.513 I'm going to go ahead and run code of grade.py, to give myself a new file. 00:25:46.513 --> 00:25:49.680 And I'm going to go ahead and start by just getting the user's score, again, 00:25:49.680 --> 00:25:51.700 on some assignment, or test, or the like. 00:25:51.700 --> 00:25:55.200 And I'm going to store it in a variable called score, equal the return 00:25:55.200 --> 00:25:58.320 value of the int function, which is going to convert whatever the user's 00:25:58.320 --> 00:26:00.610 input is when prompted for this score. 00:26:00.610 --> 00:26:04.650 So again, the user should just oblige by giving me a number like zero, or one, 00:26:04.650 --> 00:26:09.090 or two, or hopefully much higher than that, like 97, 98, 99, 100, 00:26:09.090 --> 00:26:13.330 assuming the test or assessment is out of 100 percentage points. 00:26:13.330 --> 00:26:17.220 Now, how could I go about assigning a grade to the student's score? 00:26:17.220 --> 00:26:19.710 Well in the US, it's very commonly the case 00:26:19.710 --> 00:26:22.500 that if you get between a 90 and 100, that's an A. 00:26:22.500 --> 00:26:29.160 And if it's between an 80 and a 89, it's a B. If it's 70 and 79, it's a C, 00:26:29.160 --> 00:26:32.558 and so forth, all the way down to F, which should be E, 00:26:32.558 --> 00:26:34.350 but we'll see that there's a bit of a jump. 00:26:34.350 --> 00:26:35.572 So how might I express this? 00:26:35.572 --> 00:26:36.780 Well, I can use conditionals. 00:26:36.780 --> 00:26:39.750 And I can ask a few questions and then print out the student's grade 00:26:39.750 --> 00:26:40.600 accordingly. 00:26:40.600 --> 00:26:44.040 So let me express it like this, if the student's score is 00:26:44.040 --> 00:26:47.820 greater than or equal to 90, and the student's score is 00:26:47.820 --> 00:26:51.750 less than or equal to 100, so it's in that range, let's go ahead 00:26:51.750 --> 00:26:55.980 and print out that their grade shall be an A. Because they're in the 90s, 00:26:55.980 --> 00:26:58.080 above grades range. 00:26:58.080 --> 00:27:02.580 elif the score is greater than or equal to 80, 00:27:02.580 --> 00:27:07.980 and the score is less than or equal to, say, 89, but here I have some options. 00:27:07.980 --> 00:27:11.050 Logically, I can actually express myself in any number of ways. 00:27:11.050 --> 00:27:12.800 And maybe just to be a little cleaner, I'm 00:27:12.800 --> 00:27:15.060 going to say a score is less than 90. 00:27:15.060 --> 00:27:18.300 So I'm using less than instead of less than or equal to. 00:27:18.300 --> 00:27:21.690 So I'm making sure that their boundaries between these grades are correct. 00:27:21.690 --> 00:27:26.460 Then, I'm going to go ahead and give the student a B if it's in the 80s. 00:27:26.460 --> 00:27:31.770 elif score is greater than or equal to 70, and the score is less than 80, 00:27:31.770 --> 00:27:34.851 I'm going to go ahead and give them a C. 00:27:34.851 --> 00:27:40.380 elif the score is greater than or equal to 60, and the score is less than 70, 00:27:40.380 --> 00:27:43.080 I'm going to go ahead and give him a D. And here's 00:27:43.080 --> 00:27:46.380 where it's a little anomalous, at least in some schools here, else 00:27:46.380 --> 00:27:51.060 I'm going to go ahead and give them an F. So we're skipping E altogether, 00:27:51.060 --> 00:27:53.760 and we're going to give an F, instead, for the grade. 00:27:53.760 --> 00:27:55.080 So that's the catch-all. 00:27:55.080 --> 00:27:58.020 And I think, logically, I've gotten this correct, 00:27:58.020 --> 00:28:00.360 at least based on where I went to school growing up, 00:28:00.360 --> 00:28:03.950 such that it's going to give an A, or a B, or a C, or a D, 00:28:03.950 --> 00:28:06.512 else it's going to assume that you got an F. 00:28:06.512 --> 00:28:08.220 Well, let's try just a few of these here. 00:28:08.220 --> 00:28:10.260 Let's run Python of grade.py. 00:28:10.260 --> 00:28:13.650 My score is, let's start strong, 100. 00:28:13.650 --> 00:28:17.040 I got an A. Didn't do as well the next time, maybe it's a 95-- 00:28:17.040 --> 00:28:21.270 still an A. Starting to slip further, so I got an 89 the next time. 00:28:21.270 --> 00:28:25.320 That's now, say, a B. And let's say I really had a bad week, 00:28:25.320 --> 00:28:27.030 and it's now a 71. 00:28:27.030 --> 00:28:31.830 That's now a C. Or I didn't even submit it at all, that's an F, altogether. 00:28:31.830 --> 00:28:32.940 So it seems to work. 00:28:32.940 --> 00:28:35.070 That's not really an exhaustive test, but at least 00:28:35.070 --> 00:28:38.810 based on some sampling there, my code seems to work as I expect. 00:28:38.810 --> 00:28:40.560 But let's see if we can't tighten this up. 00:28:40.560 --> 00:28:41.220 It's not wrong. 00:28:41.220 --> 00:28:42.070 It's correct. 00:28:42.070 --> 00:28:44.070 And, indeed, according to my own specifications, 00:28:44.070 --> 00:28:45.510 I dare say this code is correct. 00:28:45.510 --> 00:28:46.710 But can we tighten it up? 00:28:46.710 --> 00:28:50.500 Can we reduce the probability of bugs, now or down the line? 00:28:50.500 --> 00:28:52.230 Can we increase the readability of it? 00:28:52.230 --> 00:28:54.030 And can we increase the efficiency of it? 00:28:54.030 --> 00:28:57.690 Can we get the computer to have to answer fewer questions 00:28:57.690 --> 00:28:59.375 and still get the same result? 00:28:59.375 --> 00:29:00.750 Well, let's see what we might do. 00:29:00.750 --> 00:29:03.690 Let me just switch things up, if only to demonstrate that we can 00:29:03.690 --> 00:29:05.760 use these symbols in different ways. 00:29:05.760 --> 00:29:10.200 I could say, as I've done, if score is greater than or equal to 90. 00:29:10.200 --> 00:29:12.570 But I can actually do this, I can flip it around. 00:29:12.570 --> 00:29:14.800 Instead of saying greater than or equal to, 00:29:14.800 --> 00:29:19.060 let's say 90 is less than or equal to score. 00:29:19.060 --> 00:29:23.980 And here, let's say if 80 is less than or equal to score. 00:29:23.980 --> 00:29:28.180 And here, 70 is less than or equal to score. 00:29:28.180 --> 00:29:31.390 And then, lastly, 60 is less than or equal to score. 00:29:31.390 --> 00:29:33.370 So it's the same thing, logically. 00:29:33.370 --> 00:29:36.460 I'm just switching things around, just like you could do on paper pencil 00:29:36.460 --> 00:29:37.670 if you really wanted. 00:29:37.670 --> 00:29:39.200 But now notice this trick. 00:29:39.200 --> 00:29:42.460 And this is not possible, for those of you who have programmed in C, or C++, 00:29:42.460 --> 00:29:44.320 or Java, or other languages. 00:29:44.320 --> 00:29:48.760 Notice what I can do here is actually combine these ranges. 00:29:48.760 --> 00:29:52.000 Notice that I'm asking two questions, two Boolean expressions. 00:29:52.000 --> 00:29:57.250 Is 90 less than or equal to score, and is score less than or equal to 100? 00:29:57.250 --> 00:30:01.150 Well, Python allows you to nest these things like this, 00:30:01.150 --> 00:30:02.680 and chain them together. 00:30:02.680 --> 00:30:06.070 And just like you would on paper pencil in the real world, 00:30:06.070 --> 00:30:09.732 you can encode in Python, do this, which is just a little cleaner. 00:30:09.732 --> 00:30:11.440 It's tightening up the code a little bit. 00:30:11.440 --> 00:30:12.550 It's fewer keystrokes. 00:30:12.550 --> 00:30:13.660 It's faster to type. 00:30:13.660 --> 00:30:15.530 It's easier to read, moving forward. 00:30:15.530 --> 00:30:18.140 So that's arguably better, as well. 00:30:18.140 --> 00:30:19.450 So that's one improvement. 00:30:19.450 --> 00:30:21.422 It's largely aesthetic, in this case. 00:30:21.422 --> 00:30:23.380 It's still asking the same number of questions, 00:30:23.380 --> 00:30:26.950 but it's doing it a little more succinctly still. 00:30:26.950 --> 00:30:29.500 Well, what more could I do here next? 00:30:29.500 --> 00:30:30.730 Well, you know what? 00:30:30.730 --> 00:30:32.920 Each time I'm deciding these grades, I don't 00:30:32.920 --> 00:30:34.940 think I have to ask two questions. 00:30:34.940 --> 00:30:38.290 I don't have to ask, is it greater than 90 and less than 100? 00:30:38.290 --> 00:30:40.840 Is it greater than 80 and less than 90? 00:30:40.840 --> 00:30:45.070 If I rethink my logic, I can maybe do this better still. 00:30:45.070 --> 00:30:48.920 Let me propose that we simplify this further, and just do this. 00:30:48.920 --> 00:30:53.260 If we know that input, for the moment, is going to be within 0 and 100, 00:30:53.260 --> 00:30:54.730 we can make some assumptions. 00:30:54.730 --> 00:30:58.870 We could say something like, if the score is greater than or equal to 90, 00:30:58.870 --> 00:31:04.150 well, the student gets an A. elif the score is greater than or equal to 80, 00:31:04.150 --> 00:31:08.110 the student gets a B. elif score is greater than or equal to 70, 00:31:08.110 --> 00:31:13.930 they get a C. elif the score is greater than or equal to 60, 00:31:13.930 --> 00:31:19.940 they get a D, else they get an F. So what have I done here? 00:31:19.940 --> 00:31:23.200 Well, instead of asking two questions every time, 00:31:23.200 --> 00:31:26.320 checking the lower bounds and the upper bound of that range, 00:31:26.320 --> 00:31:31.030 I'm being a little more clever here by asking if the score is greater than 90, 00:31:31.030 --> 00:31:33.430 well, they've obviously gotten an A or better. 00:31:33.430 --> 00:31:36.070 If your score is greater than 80, well, you either 00:31:36.070 --> 00:31:40.750 deserve an A if it's really strong, or a B if it's just above 80. 00:31:40.750 --> 00:31:44.680 But because of the elif logic, we've already checked 00:31:44.680 --> 00:31:46.450 is the student's score greater than 90? 00:31:46.450 --> 00:31:50.020 And if it's not, then we're asking the question, well, is it greater than 80? 00:31:50.020 --> 00:31:54.220 So you implicitly know it's somewhere in the 80 to 89 range, 00:31:54.220 --> 00:31:58.780 else you know it's in the 70 to 79 range, else it's in the next range 00:31:58.780 --> 00:31:59.350 down. 00:31:59.350 --> 00:32:02.950 So it's a minor optimization that allows us to ask fewer questions. 00:32:02.950 --> 00:32:05.980 But again, it's making the code, arguably, a little more readable, 00:32:05.980 --> 00:32:09.580 certainly more succinct, an then, hopefully, more maintainable 00:32:09.580 --> 00:32:10.600 longer term. 00:32:10.600 --> 00:32:15.890 Any questions, then, on these types of changes, 00:32:15.890 --> 00:32:20.200 and this type of logic with our code? 00:32:20.200 --> 00:32:22.120 SPEAKER 4: What if we don't use elif at all? 00:32:22.120 --> 00:32:25.345 What if we write the code in if? 00:32:25.345 --> 00:32:27.220 DAVID MALAN: Yeah, so that's a good question, 00:32:27.220 --> 00:32:31.360 because it's actually going to have an unintended effect here. 00:32:31.360 --> 00:32:33.340 Let me get rid of the F temporarily, and just 00:32:33.340 --> 00:32:36.460 focus on A through D. If we revert to where 00:32:36.460 --> 00:32:39.190 we began today's story, with conditionals, saying if, 00:32:39.190 --> 00:32:45.070 if, if, if, now our cleverness here of using broader strokes 00:32:45.070 --> 00:32:47.680 and not using an upper and lower bound ranges 00:32:47.680 --> 00:32:51.010 is going to come back to be a downside. 00:32:51.010 --> 00:32:53.320 Let me go ahead and run Python of grade.py. 00:32:53.320 --> 00:32:56.560 And suppose my score is 95. 00:32:56.560 --> 00:32:58.120 I am so darn excited. 00:32:58.120 --> 00:33:00.520 I want my A, but nope. 00:33:00.520 --> 00:33:06.040 I just got an A, a B, a C, and a D. So logically, that's broken things. 00:33:06.040 --> 00:33:09.220 Because if you don't make these conditions mutually exclusive, 00:33:09.220 --> 00:33:13.540 every one of those questions is going to get asked, and therefore answered. 00:33:13.540 --> 00:33:16.720 And even if your grade is above a 90, it's 00:33:16.720 --> 00:33:20.140 also, logically, above an 80, above a 70, above a 60, 00:33:20.140 --> 00:33:23.580 and if I'd kept it in there, I would have failed, as well, with an F. 00:33:23.580 --> 00:33:24.920 Really good question. 00:33:24.920 --> 00:33:28.690 Other questions here, on this form of logic? 00:33:28.690 --> 00:33:30.940 SPEAKER 5: Would there be any better way to clean up 00:33:30.940 --> 00:33:33.130 even just this simple statement, like we had before, 00:33:33.130 --> 00:33:36.280 the previous one that you had with the elif? 00:33:36.280 --> 00:33:40.270 DAVID MALAN: I like your enthusiasm for simplifying things further. 00:33:40.270 --> 00:33:45.010 I'm going to go out on a limb here and say this is about as good as it gets, 00:33:45.010 --> 00:33:48.070 at least using only conditional statements. 00:33:48.070 --> 00:33:52.390 I can, if my mind wanders, think of a slightly more clever way 00:33:52.390 --> 00:33:54.490 to do this, maybe with something called a loop, 00:33:54.490 --> 00:33:55.902 or another programming construct. 00:33:55.902 --> 00:33:57.610 We don't have that yet in our vocabulary. 00:33:57.610 --> 00:33:59.610 But yes, there's absolutely other ways to do it. 00:33:59.610 --> 00:34:01.780 But I think not yet if we want to restrict ourselves 00:34:01.780 --> 00:34:07.120 to just words like if, and or, and else, and elif, and and, and the like. 00:34:07.120 --> 00:34:10.810 Well, let me propose that we pivot now to use another approach here 00:34:10.810 --> 00:34:12.800 that uses one other symbol that, up until now, 00:34:12.800 --> 00:34:14.409 we've not really had occasion to use. 00:34:14.409 --> 00:34:18.580 Let me propose that we implement a program that we'll call parity. 00:34:18.580 --> 00:34:22.460 In mathematics, parity can refer to whether a number is even or odd. 00:34:22.460 --> 00:34:24.530 And that's kind of an interesting question. 00:34:24.530 --> 00:34:26.863 And it turns out it can be useful in other applications, 00:34:26.863 --> 00:34:29.770 too, to just ask the question is a given number even or odd, 00:34:29.770 --> 00:34:31.300 maybe that the user typed in? 00:34:31.300 --> 00:34:33.670 And let me go ahead and write a new program 00:34:33.670 --> 00:34:38.800 called parity.py, via code parity.py in my terminal. 00:34:38.800 --> 00:34:41.560 And let me propose that we use this as an opportunity 00:34:41.560 --> 00:34:45.190 to introduce the last of those arithmetic symbols, 00:34:45.190 --> 00:34:48.800 at least most of which we're familiar with, addition, subtraction, 00:34:48.800 --> 00:34:49.900 multiplication, division. 00:34:49.900 --> 00:34:53.317 But there's been on this list before, this last one here, a percent sign. 00:34:53.317 --> 00:34:55.150 And it doesn't mean percentage in this case, 00:34:55.150 --> 00:34:57.850 when used as an operator in programming in Python. 00:34:57.850 --> 00:35:01.000 Rather, it represents the so-called modulo operator, 00:35:01.000 --> 00:35:02.260 for modular arithmetic. 00:35:02.260 --> 00:35:05.710 Or, at least in our case, we're going to use it to calculate the remainder when 00:35:05.710 --> 00:35:07.930 dividing one number by another. 00:35:07.930 --> 00:35:09.140 Well, what do I mean by that? 00:35:09.140 --> 00:35:12.070 Well, if you take a number like one divided by three, 00:35:12.070 --> 00:35:14.840 three does not go into one cleanly. 00:35:14.840 --> 00:35:16.690 So you have a remainder of one. 00:35:16.690 --> 00:35:20.140 Two divided by three has a remainder of two. 00:35:20.140 --> 00:35:24.550 Three divided by three has a remainder of zero, because it divides cleanly. 00:35:24.550 --> 00:35:30.088 Four divided by three has a remainder of one, because you can divide it in once, 00:35:30.088 --> 00:35:32.380 but then that leaves one, so it has a remainder of one. 00:35:32.380 --> 00:35:35.692 And then lastly, something like five divided by three 00:35:35.692 --> 00:35:37.150 has a remainder, of course, of two. 00:35:37.150 --> 00:35:39.700 So that's all we mean by remainder, how much is left over 00:35:39.700 --> 00:35:41.830 after dividing one number by another. 00:35:41.830 --> 00:35:46.180 Well, if I go back now to my code, and I consider how I might implement 00:35:46.180 --> 00:35:49.150 the question is this number even or odd? 00:35:49.150 --> 00:35:51.520 Let's consider how we might implement that, 00:35:51.520 --> 00:35:53.885 since it's perhaps not necessarily obvious how we 00:35:53.885 --> 00:35:55.510 can use this additional building block. 00:35:55.510 --> 00:35:58.460 But it turns out it's going to be very useful longer term. 00:35:58.460 --> 00:36:01.630 Well, let's first just get a number from the user in a variable called x. 00:36:01.630 --> 00:36:04.570 And I'm going to set that equal to the conversion to int 00:36:04.570 --> 00:36:08.890 of whatever the user inputs, after asking them what's x, question mark. 00:36:08.890 --> 00:36:10.840 And we've done that before, many times. 00:36:10.840 --> 00:36:14.750 How do I now determine if x is even or odd? 00:36:14.750 --> 00:36:19.270 Well, it turns out, if I have access to a programmatic operator that tells me 00:36:19.270 --> 00:36:21.742 the remainder, I think I can do this. 00:36:21.742 --> 00:36:23.200 In fact, let me just ask the group. 00:36:23.200 --> 00:36:25.480 And this is just from grade school math, perhaps, 00:36:25.480 --> 00:36:28.750 what does it mean for a number to be even, ? 00:36:28.750 --> 00:36:36.235 To be clear, a number like 0, 2, 4, 6, 8, 10, 12, 14, 16, 00:36:36.235 --> 00:36:37.360 those are all even numbers. 00:36:37.360 --> 00:36:38.652 But what does that really mean? 00:36:38.652 --> 00:36:40.960 Elena, if I'm saying that right? 00:36:40.960 --> 00:36:43.990 ELENA: Even numbers that can divide it exactly by two. 00:36:43.990 --> 00:36:48.275 For example, 2, 4, 6, 8, and 10, and-- 00:36:48.275 --> 00:36:49.150 DAVID MALAN: Perfect. 00:36:49.150 --> 00:36:51.040 And we could go on all day long, literally, 00:36:51.040 --> 00:36:53.332 since there's an infinite number of those even numbers. 00:36:53.332 --> 00:36:56.260 But it's nice that you formulated it in terms of a question 00:36:56.260 --> 00:36:58.240 that we can ask very clearly. 00:36:58.240 --> 00:37:01.360 Is this number cleanly divided by two? 00:37:01.360 --> 00:37:05.460 That is, can we divide it by two with no remainder, a remainder of zero? 00:37:05.460 --> 00:37:09.430 Well, that's perfect, because if we have this operator, this percent sign, that 00:37:09.430 --> 00:37:13.300 allows us to answer just that, what is the remainder, we can presumably check 00:37:13.300 --> 00:37:15.790 is the remainder zero, or is it one? 00:37:15.790 --> 00:37:19.120 Do we have nothing left over, or do we have one left over? 00:37:19.120 --> 00:37:20.080 Well, let's ask that. 00:37:20.080 --> 00:37:28.568 If x divided by two has a remainder of zero, as Elena proposes, let's go ahead 00:37:28.568 --> 00:37:30.610 and print out something like quote, unquote even. 00:37:30.610 --> 00:37:32.410 And just say as much to the user. 00:37:32.410 --> 00:37:35.380 else, I think we can assume that if a number's not even, 00:37:35.380 --> 00:37:38.660 it's going to be odd, if it's, indeed, an integer. 00:37:38.660 --> 00:37:41.590 So I'm going to go ahead and print out quote, unquote odd instead. 00:37:41.590 --> 00:37:45.100 And let's go ahead and now run Python of parity.py in my prompt. 00:37:45.100 --> 00:37:45.760 What's x? 00:37:45.760 --> 00:37:46.840 Let's start with two. 00:37:46.840 --> 00:37:48.220 Two is, in fact, even. 00:37:48.220 --> 00:37:49.390 Let's start with four. 00:37:49.390 --> 00:37:50.560 Four is, in fact, even. 00:37:50.560 --> 00:37:53.750 Let's get interesting with three. 00:37:53.750 --> 00:37:54.838 Three is now odd. 00:37:54.838 --> 00:37:57.880 And I think we could do that all day long and hopefully get back, indeed, 00:37:57.880 --> 00:37:59.770 exactly that answer. 00:37:59.770 --> 00:38:02.180 But what more could we do here? 00:38:02.180 --> 00:38:03.910 How could we improve upon this? 00:38:03.910 --> 00:38:08.050 Well, recall that we have the ability to invent our own functions. 00:38:08.050 --> 00:38:10.270 And let me just propose, for the sake of discussion, 00:38:10.270 --> 00:38:12.145 that we're going to eventually find that it's 00:38:12.145 --> 00:38:14.600 useful to be able to determine if a number is even or odd. 00:38:14.600 --> 00:38:17.080 And so we'd like to have that functionality built-in. 00:38:17.080 --> 00:38:20.230 And I don't think Python has a function for telling me just that. 00:38:20.230 --> 00:38:23.240 But I can invent it using code like just this. 00:38:23.240 --> 00:38:26.770 So let me go into my earlier version here. 00:38:26.770 --> 00:38:29.810 And let me propose that we do this. 00:38:29.810 --> 00:38:32.680 Let me go ahead and write a main function. 00:38:32.680 --> 00:38:36.130 I'm going to get back into that habit of defining a main function to represent 00:38:36.130 --> 00:38:37.457 the main part of my program. 00:38:37.457 --> 00:38:39.040 And I'm going to do what I did before. 00:38:39.040 --> 00:38:41.710 I'm going to get an integer from the user's input, 00:38:41.710 --> 00:38:44.680 asking them what's x, question mark. 00:38:44.680 --> 00:38:46.420 And then I'm going to ask this question. 00:38:46.420 --> 00:38:48.667 For the moment, I'm going to naively assume 00:38:48.667 --> 00:38:50.500 that the function already exists, but that's 00:38:50.500 --> 00:38:52.390 a useful problem-solving technique. 00:38:52.390 --> 00:38:55.270 Even if I have no idea yet where I'm going with this, 00:38:55.270 --> 00:38:58.750 how I'm going to invent a function that determines if a number is even, 00:38:58.750 --> 00:39:01.780 I'm just going to assume that there's a function called "is even," 00:39:01.780 --> 00:39:04.240 and I'm going to call it, blindly, like this. 00:39:04.240 --> 00:39:11.470 If is even, passing in x, then go ahead and print quote, unquote even. 00:39:11.470 --> 00:39:17.650 So if this magical function called "is even" returns true, as its return value 00:39:17.650 --> 00:39:19.960 I am going to print out that it's even. 00:39:19.960 --> 00:39:23.710 Else, otherwise, I'm going to assume that it's, of course, odd. 00:39:23.710 --> 00:39:27.625 Now the one problem with this program, even if I call main over here, 00:39:27.625 --> 00:39:30.010 is that is even does not exist. 00:39:30.010 --> 00:39:32.620 And this program would break if I ran it right now. 00:39:32.620 --> 00:39:33.530 But that's OK. 00:39:33.530 --> 00:39:35.990 I have the ability, recall, to invent my own function. 00:39:35.990 --> 00:39:39.970 So let me define, with def, a function called "is even." 00:39:39.970 --> 00:39:42.760 I want this function to take an argument. 00:39:42.760 --> 00:39:45.550 And I'm going to call it n, just a number, generically. 00:39:45.550 --> 00:39:46.690 I could call it x. 00:39:46.690 --> 00:39:49.640 But again, I don't want to confuse myself as to which x is which. 00:39:49.640 --> 00:39:52.100 So I'm going to give it a different name, and that's fine. 00:39:52.100 --> 00:39:54.700 I'm just going to call it, more generically, n for number. 00:39:54.700 --> 00:39:56.590 And then I'm going to do this. 00:39:56.590 --> 00:40:03.490 I'm going to say if N % two equals equals zero, just like before, then, 00:40:03.490 --> 00:40:06.520 and here's the magic, you, the programmer, 00:40:06.520 --> 00:40:10.660 can actually return what are called Boolean values. 00:40:10.660 --> 00:40:16.430 We've seen in Python that Python has stirs or strings, ints or integers, 00:40:16.430 --> 00:40:19.000 floats or floating point values, all of which 00:40:19.000 --> 00:40:21.520 are different types of data in Python. 00:40:21.520 --> 00:40:26.210 Python also has a fourth data type called bool for a Boolean value. 00:40:26.210 --> 00:40:29.470 And even though this is just adding to our list, the nice thing about bools 00:40:29.470 --> 00:40:32.890 is that they can only be true or false. 00:40:32.890 --> 00:40:36.280 An int can be any number of an infinite possible values. 00:40:36.280 --> 00:40:39.040 A bool can only be true or false. 00:40:39.040 --> 00:40:43.460 And it must be capital T and capital F if you're writing itself. 00:40:43.460 --> 00:40:46.030 So if I go back now to my code, and I consider 00:40:46.030 --> 00:40:49.480 exactly what I want to return here. 00:40:49.480 --> 00:40:53.560 Well, if n % two equals equals zero, that is, 00:40:53.560 --> 00:40:58.270 if n divided by two has a remainder of zero, well, I think it's even, 00:40:58.270 --> 00:40:59.750 to, Elena, your definition. 00:40:59.750 --> 00:41:05.380 So let's return true, capital T. else, if it doesn't have a remainder of zero, 00:41:05.380 --> 00:41:08.440 I'm pretty sure, mathematically, it's got to have a remainder of one. 00:41:08.440 --> 00:41:09.400 But it doesn't matter. 00:41:09.400 --> 00:41:13.210 I know it's not even, so I'm going to return false. 00:41:13.210 --> 00:41:18.610 And we return false, instead capital F. And now that we've defined both main 00:41:18.610 --> 00:41:23.350 and is even, and I'm calling main at the bottom, I think I've got this right. 00:41:23.350 --> 00:41:25.960 Python of parity.py, Enter. 00:41:25.960 --> 00:41:26.650 What's x? 00:41:26.650 --> 00:41:28.780 Let's try something simple, like two. 00:41:28.780 --> 00:41:29.890 And it's even. 00:41:29.890 --> 00:41:30.850 Let's do it again. 00:41:30.850 --> 00:41:31.420 What's x? 00:41:31.420 --> 00:41:32.560 How about four? 00:41:32.560 --> 00:41:33.100 Even. 00:41:33.100 --> 00:41:34.480 Once more, what's x? 00:41:34.480 --> 00:41:35.740 How about three? 00:41:35.740 --> 00:41:36.910 And it's odd. 00:41:36.910 --> 00:41:38.140 Now, what have I done here? 00:41:38.140 --> 00:41:42.700 I've just made the point that if I want to create my own function called "is 00:41:42.700 --> 00:41:44.410 even," that answers this question for me, 00:41:44.410 --> 00:41:47.350 that I can now use, in this program, and heck, maybe future programs 00:41:47.350 --> 00:41:51.190 that I write, I now have a function that no one gave me, 00:41:51.190 --> 00:41:53.290 I gave myself, that I can use and reuse. 00:41:53.290 --> 00:41:55.580 And I can even, perhaps, share it with others. 00:41:55.580 --> 00:41:59.560 I'm using that function now on line three, just to make a decision. 00:41:59.560 --> 00:42:01.360 I'm using a conditional up there. 00:42:01.360 --> 00:42:05.140 And my Boolean expression, something that's true or false, 00:42:05.140 --> 00:42:08.800 is going to be not something explicit, like x less than y, 00:42:08.800 --> 00:42:11.020 or y greater than x, or the like. 00:42:11.020 --> 00:42:13.180 It's going to be a function call. 00:42:13.180 --> 00:42:15.790 I'm using a function as my Boolean expression. 00:42:15.790 --> 00:42:18.160 But that's OK because I know, because I wrote it, 00:42:18.160 --> 00:42:23.580 that that function "is even" returns true or it returns false. 00:42:23.580 --> 00:42:26.750 And that's all I need in a conditional to make a decision 00:42:26.750 --> 00:42:29.810 to print even or print odd. 00:42:29.810 --> 00:42:33.110 So let me pause here to see if there's any questions now on how I've 00:42:33.110 --> 00:42:36.875 implemented "is even," using this bool. 00:42:36.875 --> 00:42:38.000 SPEAKER 6: Hello, hi David. 00:42:38.000 --> 00:42:41.120 First of all, thank you for this wonderful class the day 00:42:41.120 --> 00:42:43.340 before yesterday and today, sir. 00:42:43.340 --> 00:42:47.720 I have just one query, based on the background of Java. 00:42:47.720 --> 00:42:50.810 There, when we used to pass the argument, 00:42:50.810 --> 00:42:53.940 we can also pass the address of the variables. 00:42:53.940 --> 00:42:57.120 So is there any sort of this concept in Python? 00:42:57.120 --> 00:42:58.370 DAVID MALAN: Short answer, no. 00:42:58.370 --> 00:43:02.300 Those who are unfamiliar with Java or other languages, or C, or C++, 00:43:02.300 --> 00:43:06.230 there's generally ways to pass values in different mechanisms that allow you, 00:43:06.230 --> 00:43:07.700 or disallow you, to change them. 00:43:07.700 --> 00:43:08.897 In Python, no. 00:43:08.897 --> 00:43:11.480 Everything we're going to see is actually, in fact, an object. 00:43:11.480 --> 00:43:13.890 But more on that down the line. 00:43:13.890 --> 00:43:17.960 How about time for one more question here on these bools and these 00:43:17.960 --> 00:43:19.700 "is evens." 00:43:19.700 --> 00:43:23.720 SPEAKER 7: So I actually had a question about defining a function, 00:43:23.720 --> 00:43:24.680 if that's OK. 00:43:24.680 --> 00:43:25.430 DAVID MALAN: Sure. 00:43:25.430 --> 00:43:29.030 SPEAKER 7: So if you define one, within your code, like you made it up, 00:43:29.030 --> 00:43:33.230 are you allowed to use the dot operator like we did name dot strip, 00:43:33.230 --> 00:43:34.295 and use it like that? 00:43:34.295 --> 00:43:35.420 DAVID MALAN: Good question. 00:43:35.420 --> 00:43:37.880 If you've created your own function, can you 00:43:37.880 --> 00:43:42.350 use other functions, like dot strip, or dot title, or dot capitalize, 00:43:42.350 --> 00:43:44.210 that we've seen in the past? 00:43:44.210 --> 00:43:46.580 You can use those on strings. 00:43:46.580 --> 00:43:49.110 Those functions come with strings. 00:43:49.110 --> 00:43:51.980 You can't necessarily use them on your own functions, 00:43:51.980 --> 00:43:56.030 unless your function returns a string, for the examples you gave. 00:43:56.030 --> 00:43:57.350 I'm returning a bool. 00:43:57.350 --> 00:44:00.140 Bools have no notion of white space to the left or the right. 00:44:00.140 --> 00:44:02.207 You can't call strip, you can't call capitalize. 00:44:02.207 --> 00:44:04.040 But if you were writing a different function 00:44:04.040 --> 00:44:06.020 that returns a string, absolutely. 00:44:06.020 --> 00:44:08.015 You could use those functions, as well. 00:44:08.015 --> 00:44:10.640 Well, let me turn our attention, if I may, back to this example 00:44:10.640 --> 00:44:13.220 here, and consider, as we now frequently do, 00:44:13.220 --> 00:44:15.920 can we improve on the design of this code? 00:44:15.920 --> 00:44:18.290 Can I make this particular program better? 00:44:18.290 --> 00:44:19.340 And I can. 00:44:19.340 --> 00:44:20.630 There's a couple of ways here. 00:44:20.630 --> 00:44:24.320 And I'll show you something that's now generally known as something Pythonic. 00:44:24.320 --> 00:44:26.840 There's actually this term of art, in the Python world, 00:44:26.840 --> 00:44:31.468 where something is Pythonic if it's just the way you do things in Python. 00:44:31.468 --> 00:44:33.260 Which is to say, we've seen already there's 00:44:33.260 --> 00:44:35.480 so many different ways to solve certain problems. 00:44:35.480 --> 00:44:38.000 And in the Python community of programmers, 00:44:38.000 --> 00:44:41.990 there tend to be some ways that are smiled upon more than others. 00:44:41.990 --> 00:44:45.560 And they tend to relate to features that maybe only Python has, 00:44:45.560 --> 00:44:46.785 but not other languages. 00:44:46.785 --> 00:44:49.910 And here's some syntax that you might not have seen in languages like Java, 00:44:49.910 --> 00:44:52.470 or C, or C++ if you've programmed before. 00:44:52.470 --> 00:44:55.700 And if you've never programmed before, this too is going to be new. 00:44:55.700 --> 00:45:02.420 Instead of asking a question like this, if else using four lines, in Python, 00:45:02.420 --> 00:45:07.520 you can actually collapse this into just one more elegant line, if you will. 00:45:07.520 --> 00:45:12.320 Instead of asking if n divided by two has a remainder of zero, 00:45:12.320 --> 00:45:15.390 return true, else return false. 00:45:15.390 --> 00:45:23.150 Let me delete all of that and just say this, return true if n divided by two 00:45:23.150 --> 00:45:27.660 has a remainder of zero, else return false. 00:45:27.660 --> 00:45:30.140 Now those of you who do have prior programming experience 00:45:30.140 --> 00:45:31.940 might actually think this is kind of cool. 00:45:31.940 --> 00:45:35.960 You can condense, from four lines into one line, that very same thought. 00:45:35.960 --> 00:45:39.260 And one of the reasons why Python is popular is that it does 00:45:39.260 --> 00:45:41.270 tend to read rather like English. 00:45:41.270 --> 00:45:44.660 It's not quite as user-friendly as most English, or most human languages. 00:45:44.660 --> 00:45:48.470 But notice, now, the line does rather say what you mean. 00:45:48.470 --> 00:45:55.190 Return true if n divided by two has a remainder of zero, else false. 00:45:55.190 --> 00:45:58.820 That's pretty darn close to something you might say, logically, in English, 00:45:58.820 --> 00:46:02.060 be it about even and odd or really anything else. 00:46:02.060 --> 00:46:04.280 So that program is going to work exactly the same. 00:46:04.280 --> 00:46:06.650 Python of parity.py, let me type in two. 00:46:06.650 --> 00:46:07.520 It's still even. 00:46:07.520 --> 00:46:08.600 Let me type in three. 00:46:08.600 --> 00:46:09.830 It's still odd. 00:46:09.830 --> 00:46:12.180 But I can refine this even further. 00:46:12.180 --> 00:46:15.260 And again, consistent with this idea of not just writing correct code, 00:46:15.260 --> 00:46:19.820 but writing better and better code, but still keeping it readable, 00:46:19.820 --> 00:46:22.730 I can do one even better than this. 00:46:22.730 --> 00:46:25.760 Notice this value here is my Boolean expression. 00:46:25.760 --> 00:46:28.640 And it is going to evaluate to true or false. 00:46:28.640 --> 00:46:33.800 Is n divided by two having a remainder of zero or not? 00:46:33.800 --> 00:46:35.940 That is, by definition, a Boolean expression. 00:46:35.940 --> 00:46:39.600 It has a yes/no answer, a true/false answer. 00:46:39.600 --> 00:46:45.290 Well, if your Boolean expression itself has a true or false answer, 00:46:45.290 --> 00:46:48.740 why are you asking a question in the first place? 00:46:48.740 --> 00:46:50.270 Why ask if? 00:46:50.270 --> 00:46:51.770 Why say else? 00:46:51.770 --> 00:46:57.140 Just return the value of your own Boolean expression. 00:46:57.140 --> 00:47:01.670 And perhaps the tightest version, the most succinct, and still readable, 00:47:01.670 --> 00:47:05.450 version of this code would be to delete this whole line, Pythonic 00:47:05.450 --> 00:47:12.530 though it is, and just return n modulo two equals equals zero. 00:47:12.530 --> 00:47:15.530 If it helps, let me add parentheses temporarily, 00:47:15.530 --> 00:47:18.910 because what's going to happen in parentheses will happen first. 00:47:18.910 --> 00:47:24.160 n divided by two either does or does not have a remainder of zero. 00:47:24.160 --> 00:47:25.990 If it does, the answer is true. 00:47:25.990 --> 00:47:28.130 If it doesn't, the answer is false. 00:47:28.130 --> 00:47:31.310 So just return the question, if you will. 00:47:31.310 --> 00:47:35.020 You don't need to wrap it, explicitly, with an if and an else. 00:47:35.020 --> 00:47:37.780 And in fact, because of order of operations, 00:47:37.780 --> 00:47:39.620 you don't even need the parentheses. 00:47:39.620 --> 00:47:45.370 So now this is perhaps the most elegant way to implement this same idea. 00:47:45.370 --> 00:47:46.540 Now, which is better? 00:47:46.540 --> 00:47:47.870 This is pretty darn good. 00:47:47.870 --> 00:47:51.010 And it's hard to take fault with this because it's so very succinct. 00:47:51.010 --> 00:47:54.250 But it's perfectly OK, and just as correct, 00:47:54.250 --> 00:47:56.500 to have an if and then an else. 00:47:56.500 --> 00:47:59.260 Even though it might be four total lines, if that helps 00:47:59.260 --> 00:48:01.480 you think about your code more clearly, and it helps 00:48:01.480 --> 00:48:04.100 other people reason about it, as well. 00:48:04.100 --> 00:48:06.490 So it turns out there's another syntax that you 00:48:06.490 --> 00:48:08.920 can use to implement the same idea of a conditional, 00:48:08.920 --> 00:48:12.910 whereby you do something optionally, based on the answer to some Boolean 00:48:12.910 --> 00:48:13.720 expression. 00:48:13.720 --> 00:48:17.020 And the keyword that you can now use, in recent versions of Python, 00:48:17.020 --> 00:48:18.610 is called this-- match. 00:48:18.610 --> 00:48:21.850 Match is a mechanism that, if you've programmed before, is similar in spirit 00:48:21.850 --> 00:48:24.340 to something called switch in other languages. 00:48:24.340 --> 00:48:28.450 For instance, let me go ahead here and close out parity.py And let me go ahead 00:48:28.450 --> 00:48:31.750 and create a new file called house.py. 00:48:31.750 --> 00:48:33.700 And in house.py, I think what we're going 00:48:33.700 --> 00:48:37.243 to do is try to implement a program that prompts the user for their name, 00:48:37.243 --> 00:48:39.160 and then just outputs what house they're known 00:48:39.160 --> 00:48:41.110 to be in in the world of Harry Potter. 00:48:41.110 --> 00:48:43.040 So for instance, let me go ahead and do this. 00:48:43.040 --> 00:48:46.450 Let me give myself a variable called name, set it equal to the return 00:48:46.450 --> 00:48:47.860 value of the input function. 00:48:47.860 --> 00:48:50.890 And I'll say something like, what's your name, question mark. 00:48:50.890 --> 00:48:52.750 And then after that, I'm just going to use 00:48:52.750 --> 00:48:58.210 a traditional if, elif, else construct to decide what house this person is in. 00:48:58.210 --> 00:49:03.100 So let me say if name equals equals, say Harry, as in Harry Potter, well, 00:49:03.100 --> 00:49:06.280 let's go ahead and print out Harry's house, which is Gryffindor 00:49:06.280 --> 00:49:08.060 in the world of Harry Potter. 00:49:08.060 --> 00:49:11.890 elif the name is, instead, Hermione, then 00:49:11.890 --> 00:49:15.280 go ahead and print out also quote, unquote Gryffindor, 00:49:15.280 --> 00:49:16.750 as she's in the same house, too. 00:49:16.750 --> 00:49:19.900 elif name equals equals Ron, let's go ahead 00:49:19.900 --> 00:49:23.487 and similarly print out Gryffindor quote, unquote. 00:49:23.487 --> 00:49:25.570 And let's make this a little more interesting now. 00:49:25.570 --> 00:49:29.230 elif name equals quote, unquote how about Draco? 00:49:29.230 --> 00:49:32.110 Draco Malfoy, in the books-- let's go ahead and print out quote, 00:49:32.110 --> 00:49:33.760 unquote Slytherin. 00:49:33.760 --> 00:49:36.640 And just in case someone else's name gets inputted, 00:49:36.640 --> 00:49:39.550 for now, let's just suppose that we don't recognize them, 00:49:39.550 --> 00:49:41.890 and say, by default, else print out quote, 00:49:41.890 --> 00:49:44.530 unquote who, question mark, just to convey 00:49:44.530 --> 00:49:48.130 that we don't actually have a hard-coded response to that particular name. 00:49:48.130 --> 00:49:52.635 Let me go ahead, now, and run this as Python of house.py, Enter. 00:49:52.635 --> 00:49:54.760 And I'll go ahead and type in something like Harry. 00:49:54.760 --> 00:49:57.250 And voila, we see that Harry is, indeed, in Gryffindor. 00:49:57.250 --> 00:50:00.040 Let's run it one more time, Python of house.py. 00:50:00.040 --> 00:50:01.690 Let's type in Draco this time. 00:50:01.690 --> 00:50:02.500 Slytherin. 00:50:02.500 --> 00:50:05.140 And now, let's type in an unrecognized name. 00:50:05.140 --> 00:50:07.540 Let's go ahead and rerun Python of house.py. 00:50:07.540 --> 00:50:10.000 And let's go ahead and type in Padma, Enter. 00:50:10.000 --> 00:50:10.570 And who? 00:50:10.570 --> 00:50:14.800 Because we haven't actually hard-coded with an elif condition in this case, 00:50:14.800 --> 00:50:17.290 what house Padma is meant to be in. 00:50:17.290 --> 00:50:19.750 Well, it turns out there's other ways to implement this. 00:50:19.750 --> 00:50:22.030 Indeed, there's some redundancy here, in that 00:50:22.030 --> 00:50:25.837 we're checking if Harry, or Hermione, or Ron are all in Gryffindor. 00:50:25.837 --> 00:50:28.420 I feel like we can at least tighten this code up a little bit, 00:50:28.420 --> 00:50:30.260 using techniques we've seen already. 00:50:30.260 --> 00:50:31.640 So let me go ahead and do this. 00:50:31.640 --> 00:50:34.370 Let me go up here and instead do something like this. 00:50:34.370 --> 00:50:37.120 Let's get rid of these two blocks of elifs, 00:50:37.120 --> 00:50:38.890 leaving just Harry's for a moment. 00:50:38.890 --> 00:50:41.980 And let's use that "or" keyword again, and say or name 00:50:41.980 --> 00:50:47.080 equals equals quote, unquote Hermione, or name equals quote, unquote Ron, 00:50:47.080 --> 00:50:51.370 thereby consolidating all three cases, if you will, into just one 00:50:51.370 --> 00:50:52.360 if statement. 00:50:52.360 --> 00:50:55.270 Then we still have a separate elif for Draco because he's not, 00:50:55.270 --> 00:50:56.230 in fact, in Gryffindor. 00:50:56.230 --> 00:50:59.260 And then the final else to catch anyone else. 00:50:59.260 --> 00:51:03.280 Let me go ahead now and run this version of the program, Python of house.py. 00:51:03.280 --> 00:51:05.470 I'll type in Hermione this time. 00:51:05.470 --> 00:51:07.030 She, too, is still in Gryffindor. 00:51:07.030 --> 00:51:08.170 Let me try it with Ron. 00:51:08.170 --> 00:51:10.582 And that, too, still seems to be correct. 00:51:10.582 --> 00:51:13.540 Well, it turns out there's another approach altogether that can perhaps 00:51:13.540 --> 00:51:16.000 make your code a little less verbose. 00:51:16.000 --> 00:51:18.790 You could imagine how complicated this code might 00:51:18.790 --> 00:51:21.940 get if we had not just Harry, and Hermione, and Ron, but a whole bunch 00:51:21.940 --> 00:51:25.030 of other names as well, for Gryffindor, for Slytherin, and for all 00:51:25.030 --> 00:51:26.650 of the other Hogwarts houses. 00:51:26.650 --> 00:51:29.737 So you could imagine that code just getting pretty unwieldy pretty fast. 00:51:29.737 --> 00:51:31.570 Well, it turns out another technique you can 00:51:31.570 --> 00:51:34.940 use is, indeed, this keyword called match, which is very similar in spirit, 00:51:34.940 --> 00:51:36.130 but the syntax is different. 00:51:36.130 --> 00:51:39.580 And it allows you to express the same ideas a little more compactly. 00:51:39.580 --> 00:51:41.620 So let me go back to house.py. 00:51:41.620 --> 00:51:45.700 And let me propose that I get rid of my current if, elif, else approach, 00:51:45.700 --> 00:51:47.080 and instead do this. 00:51:47.080 --> 00:51:51.070 Literally use the keyword match, and type the name of the variable, 00:51:51.070 --> 00:51:53.055 or value, that we want to match on. 00:51:53.055 --> 00:51:55.180 And then I'm going to go ahead and include a colon. 00:51:55.180 --> 00:51:58.240 And then underneath that, I'm going to include, literally, 00:51:58.240 --> 00:51:59.740 a keyword called case. 00:51:59.740 --> 00:52:02.290 And the first case I want to consider is going to be Harry. 00:52:02.290 --> 00:52:05.690 And I'm going to put Harry in quotes, because it's a string or a stir. 00:52:05.690 --> 00:52:08.350 And I'm going to have another colon at the end of this line. 00:52:08.350 --> 00:52:11.020 And indented under that one, I'm going to go ahead and, for now, 00:52:11.020 --> 00:52:13.990 print out Gryffindor, which, of course, is Harry's house. 00:52:13.990 --> 00:52:17.590 Otherwise, I'm going to have another case for quote, unquote Hermione. 00:52:17.590 --> 00:52:20.350 And similarly, I'm going to have under that indented, 00:52:20.350 --> 00:52:23.560 print quote, unquote Gryffindor, close quote. 00:52:23.560 --> 00:52:27.740 Now I'm going to have another case for Ron, also in quotes, with a colon. 00:52:27.740 --> 00:52:29.950 Now print quote, unquote Gryffindor. 00:52:29.950 --> 00:52:33.122 And now I'm going to have a other case for, let's say, Draco. 00:52:33.122 --> 00:52:35.830 This one gets a little more interesting because Draco, of course, 00:52:35.830 --> 00:52:37.750 now is in Slytherin. 00:52:37.750 --> 00:52:40.830 And then I'm going to go ahead and leave it as that for now. 00:52:40.830 --> 00:52:44.080 So let me go ahead and save this file, and go back down to my terminal window, 00:52:44.080 --> 00:52:46.930 running Python of house.py, Enter. 00:52:46.930 --> 00:52:48.485 And let's go ahead and try Harry. 00:52:48.485 --> 00:52:50.110 And he seems still to be in Gryffindor. 00:52:50.110 --> 00:52:52.810 Let's run it again for Hermione, Enter. 00:52:52.810 --> 00:52:53.560 Gryffindor. 00:52:53.560 --> 00:52:56.653 Let's skip ahead to Draco, and type in Draco's name. 00:52:56.653 --> 00:52:57.820 He is, indeed, in Slytherin. 00:52:57.820 --> 00:53:00.790 Now let's try another name that we haven't handled 00:53:00.790 --> 00:53:03.310 a case for, like Padma again, Enter. 00:53:03.310 --> 00:53:04.540 And we're just ignored. 00:53:04.540 --> 00:53:07.660 There's no output whatsoever because there wasn't a case for Padma. 00:53:07.660 --> 00:53:11.440 Now we could, of course, go back in and explicitly add one for Padma. 00:53:11.440 --> 00:53:14.440 But what if we, similarly to the else construct, 00:53:14.440 --> 00:53:18.700 just want a catchall that handles anyone whose name is not explicitly specified? 00:53:18.700 --> 00:53:22.150 Well, turns out the syntax for that, using this new match statement, 00:53:22.150 --> 00:53:24.730 is to still have another case, but then to use 00:53:24.730 --> 00:53:28.480 this single underscore character, which is used in other contexts in Python. 00:53:28.480 --> 00:53:32.440 But for here, it's meant to say whatever case has not yet been handled, 00:53:32.440 --> 00:53:35.410 go ahead and print out, as we did before, for instance, 00:53:35.410 --> 00:53:38.900 quote, unquote who, with a question mark at the end. 00:53:38.900 --> 00:53:42.310 Now let's go ahead and rerun this Python of house.py. 00:53:42.310 --> 00:53:43.668 I'll type Padma's name again. 00:53:43.668 --> 00:53:45.460 And this time, I think we're at least going 00:53:45.460 --> 00:53:48.250 to get an explicit response indicating who, 00:53:48.250 --> 00:53:50.920 whereas previously we did not have the equivalent of that. 00:53:50.920 --> 00:53:53.440 Now, I think we've regressed a little bit. 00:53:53.440 --> 00:53:56.590 We went from tightening things up by putting Harry, and Hermione, 00:53:56.590 --> 00:53:59.650 and Ron all on the same line in the same if statement. 00:53:59.650 --> 00:54:02.780 But here, we have now three case statements, again, for all three 00:54:02.780 --> 00:54:03.280 of those. 00:54:03.280 --> 00:54:05.950 Well, we can tighten this code up, as well. 00:54:05.950 --> 00:54:08.240 But the syntax is going to be a little bit different. 00:54:08.240 --> 00:54:12.160 I'm going to go ahead and delete these two middle cases for Hermione and Ron. 00:54:12.160 --> 00:54:15.320 And then up here, next to Harry's name, before the colon, 00:54:15.320 --> 00:54:18.070 I'm going to go ahead and use a single vertical bar, and then 00:54:18.070 --> 00:54:19.810 a quote, unquote Hermione. 00:54:19.810 --> 00:54:23.110 Then another single bar and do quote, unquote Ron. 00:54:23.110 --> 00:54:26.140 And this is how, using this relatively new match statement, 00:54:26.140 --> 00:54:30.220 you can say the equivalent of Harry, or Hermione, or Ron, 00:54:30.220 --> 00:54:33.640 but more concisely than you could using an if statement 00:54:33.640 --> 00:54:35.870 alone, as we implemented it previously. 00:54:35.870 --> 00:54:40.210 So now, one final run of the program with Python of house.py. 00:54:40.210 --> 00:54:42.490 Let's make sure that Harry is still in Gryffindor. 00:54:42.490 --> 00:54:44.920 Let's make sure that Hermione is still in Gryffindor. 00:54:44.920 --> 00:54:46.990 Let's make sure that Ron is still in Gryffindor. 00:54:46.990 --> 00:54:48.880 And indeed, all three of them are. 00:54:48.880 --> 00:54:51.553 Now, as always with Python and programming more generally, 00:54:51.553 --> 00:54:54.220 there's going to be different ways you can solve these problems. 00:54:54.220 --> 00:54:56.290 This is just another tool in your toolkit. 00:54:56.290 --> 00:54:58.240 Arguably, it has tightened things up. 00:54:58.240 --> 00:55:00.190 Arguably, it's perhaps a little more readable 00:55:00.190 --> 00:55:02.500 because there's a little less syntax going on, 00:55:02.500 --> 00:55:05.710 a little less duplication of equal signs and elif, 00:55:05.710 --> 00:55:07.390 and elif, and elif all over the place. 00:55:07.390 --> 00:55:11.740 But ultimately, this would be an equally correct approach to that same problem. 00:55:11.740 --> 00:55:13.600 But it turns out with a match statement you 00:55:13.600 --> 00:55:16.360 can do even more powerful forms of matching, as well. 00:55:16.360 --> 00:55:20.500 Here, we've used it simply to implement the same idea as that if, elif, 00:55:20.500 --> 00:55:21.460 else construct. 00:55:21.460 --> 00:55:24.700 And it's worth noting, if you've programmed in some other language, 00:55:24.700 --> 00:55:26.200 the syntax here is, indeed, correct. 00:55:26.200 --> 00:55:28.600 You do not need, for instance, a break statement, 00:55:28.600 --> 00:55:29.950 as has been peppered throughout. 00:55:29.950 --> 00:55:32.665 And you don't need something like default, or something explicit. 00:55:32.665 --> 00:55:37.700 You, indeed, just use this underscore as your catchall at the end of the match. 00:55:37.700 --> 00:55:40.900 So just by adding in some of these new keywords 00:55:40.900 --> 00:55:45.340 here, like if, and elif, and else, we have now the ability 00:55:45.340 --> 00:55:47.320 to ask questions about values. 00:55:47.320 --> 00:55:50.140 We have the ability to analyze input from users, 00:55:50.140 --> 00:55:52.090 and ultimately make decisions about it. 00:55:52.090 --> 00:55:54.730 And these, then, where our conditionals. 00:55:54.730 --> 00:55:58.180 Lying ahead is going to be the ability for us to not only use functions, 00:55:58.180 --> 00:56:00.380 and variables, and also these conditionals, 00:56:00.380 --> 00:56:06.330 but also, next, loops-- the ability to do something, now, again and again.