WEBVTT X-TIMESTAMP-MAP=LOCAL:00:00:00.000,MPEGTS:900000 00:00:00.984 --> 00:00:03.936 [MUSIC PLAYING] 00:00:24.120 --> 00:00:27.330 DAVID MALAN: All right, this is CS50's introduction 00:00:27.330 --> 00:00:28.770 to programming with Python. 00:00:28.770 --> 00:00:29.820 My name is David Malan. 00:00:29.820 --> 00:00:31.950 And this is our week on exceptions. 00:00:31.950 --> 00:00:35.010 Exceptions in Python as well as in other programming languages 00:00:35.010 --> 00:00:37.290 refer to problems in your code. 00:00:37.290 --> 00:00:40.090 Indeed, when something is exceptional in your program, 00:00:40.090 --> 00:00:41.950 it actually doesn't mean it's a good thing. 00:00:41.950 --> 00:00:45.518 It means something has gone wrong that, ideally, you will somehow solve. 00:00:45.518 --> 00:00:47.560 So what are some of the things that can go wrong? 00:00:47.560 --> 00:00:50.520 So I'm going to go ahead and open up VS Code on my computer here. 00:00:50.520 --> 00:00:54.638 And in the terminal window, I'm going to go ahead and run code of hello.py. 00:00:54.638 --> 00:00:56.430 That's going to, of course, open up a brand 00:00:56.430 --> 00:00:59.287 new tab for me, hello.py, in which I can write my code. 00:00:59.287 --> 00:01:01.620 And let me go ahead and write some very simple code just 00:01:01.620 --> 00:01:03.190 to say hello to the world. 00:01:03.190 --> 00:01:05.430 Let's go ahead and say print "hello, world. 00:01:08.130 --> 00:01:10.470 And then let me go ahead and-- 00:01:10.470 --> 00:01:12.420 I'm forgetting to close that quote. 00:01:12.420 --> 00:01:14.670 So a mistake that you yourself might have already made 00:01:14.670 --> 00:01:17.370 or might surely in the future make-- and it's a little subtle 00:01:17.370 --> 00:01:19.320 because you might not necessarily notice that you've just 00:01:19.320 --> 00:01:20.580 missed that one character. 00:01:20.580 --> 00:01:23.400 Well, let me go ahead and somewhat optimistically 00:01:23.400 --> 00:01:28.200 go down to my terminal window now and run Python of hello.py and hit Enter. 00:01:28.200 --> 00:01:29.970 And that's the first of my errors. 00:01:29.970 --> 00:01:31.830 My gosh, I've only written one line of code. 00:01:31.830 --> 00:01:34.350 And I seem to have more lines of errors on the screen. 00:01:34.350 --> 00:01:37.090 But the salient point is this bottom-most thing here. 00:01:37.090 --> 00:01:39.030 Notice where it says syntax error. 00:01:39.030 --> 00:01:43.140 A syntax error is a problem with the code that you have typed, your syntax. 00:01:43.140 --> 00:01:45.000 Just like English and other human languages 00:01:45.000 --> 00:01:47.670 have syntax associated with them, so does my code. 00:01:47.670 --> 00:01:49.170 And it's not quite correct. 00:01:49.170 --> 00:01:50.370 Something is awry. 00:01:50.370 --> 00:01:52.380 I didn't follow the instructions properly. 00:01:52.380 --> 00:01:56.130 And it does elaborate for me, unterminated string literal. 00:01:56.130 --> 00:01:57.360 Now, that's a bit arcane. 00:01:57.360 --> 00:01:59.370 That is a bit of a confusing error message. 00:01:59.370 --> 00:02:01.800 But unterminated would generally mean that I 00:02:01.800 --> 00:02:03.960 started something but didn't stop it. 00:02:03.960 --> 00:02:05.070 I didn't terminate it. 00:02:05.070 --> 00:02:08.310 String, of course, is a sequence of text, like we've discussed before-- 00:02:08.310 --> 00:02:09.750 or stir in Python. 00:02:09.750 --> 00:02:13.020 And literal generally refers to something that you literally typed. 00:02:13.020 --> 00:02:14.100 It's not a variable. 00:02:14.100 --> 00:02:15.990 It's something like quote unquote-- 00:02:15.990 --> 00:02:18.120 or just "hello world. 00:02:18.120 --> 00:02:20.790 So the fix here, of course, is going to be 00:02:20.790 --> 00:02:24.660 to go ahead and terminate that string and actually close the quote. 00:02:24.660 --> 00:02:27.150 And if I now go back down into my terminal window 00:02:27.150 --> 00:02:31.870 and rerun Python of hello.py, now I'm saying hello to the world. 00:02:31.870 --> 00:02:36.510 So the catch with syntax errors here is that syntax errors are entirely 00:02:36.510 --> 00:02:37.560 on you to solve. 00:02:37.560 --> 00:02:40.560 A syntax error is a problem that you've got to go back into your code 00:02:40.560 --> 00:02:41.760 and fix from the get-go. 00:02:41.760 --> 00:02:43.890 You can't just kind of hope that it's going 00:02:43.890 --> 00:02:47.280 to resolve itself or expect that other parts of your code 00:02:47.280 --> 00:02:48.300 will catch it for you. 00:02:48.300 --> 00:02:50.610 Syntax errors just must be fixed. 00:02:50.610 --> 00:02:53.340 But there's a lot of other types of errors in Python 00:02:53.340 --> 00:02:55.920 that might be described as runtime errors, that 00:02:55.920 --> 00:02:57.940 happen while your code is running. 00:02:57.940 --> 00:03:01.680 And it's really up to you to write some additional code defensively 00:03:01.680 --> 00:03:05.320 to detect when those errors happen because you don't necessarily know, 00:03:05.320 --> 00:03:08.590 for instance, what input humans are going to type into your program. 00:03:08.590 --> 00:03:11.760 And so you better be ready, defensively, to accommodate things 00:03:11.760 --> 00:03:13.830 that they type or even misstype. 00:03:13.830 --> 00:03:17.100 So, for instance, let's go back over here to VS Code. 00:03:17.100 --> 00:03:20.730 And let me propose that we take a look at a new file all together. 00:03:20.730 --> 00:03:22.290 I'm going to close hello.py. 00:03:22.290 --> 00:03:26.160 And I'm going to write code of say number.py. 00:03:26.160 --> 00:03:28.710 So let's play around with some numbers in Python. 00:03:28.710 --> 00:03:32.670 And the first thing I'm going to go ahead here and do with number.py, 00:03:32.670 --> 00:03:35.970 after opening this new tab, is I think I'm going to go ahead and print-- 00:03:35.970 --> 00:03:40.350 type up a relatively simple program that maybe prompts the user for an integer, 00:03:40.350 --> 00:03:43.000 like x, and then just prints out what x is. 00:03:43.000 --> 00:03:45.930 So we're going to start simple, but, again, in starting simple, 00:03:45.930 --> 00:03:48.870 we'll be able to really see where I've done something wrong. 00:03:48.870 --> 00:03:49.600 Well, here we go. 00:03:49.600 --> 00:03:51.780 I'm going to go ahead and say a variable called 00:03:51.780 --> 00:03:57.330 x is going to get assigned the value of the return value of input, 00:03:57.330 --> 00:03:59.603 quote unquote, "what's x?" 00:03:59.603 --> 00:04:02.520 And I'm going to include a space to move the cursor over a little bit. 00:04:02.520 --> 00:04:05.550 And then, ultimately, I'm going to go ahead and-- oh, wait a minute. 00:04:05.550 --> 00:04:08.070 If I'm wanting to get an int from the user, 00:04:08.070 --> 00:04:10.530 recall that I need to do something proactively. 00:04:10.530 --> 00:04:14.760 I need to actually convert that input to an integer using 00:04:14.760 --> 00:04:16.050 the int function in Python. 00:04:16.050 --> 00:04:20.519 So now I'm passing the return value of input as the argument to int. 00:04:20.519 --> 00:04:22.980 And that will store in x, ultimately, an integer, not 00:04:22.980 --> 00:04:24.893 a string that looks like an integer. 00:04:24.893 --> 00:04:28.060 All right, let me go ahead now and just quite simply print out what this is. 00:04:28.060 --> 00:04:32.610 I'm going to go ahead and print out, quote unquote, "x is x." 00:04:32.610 --> 00:04:34.920 But I don't want to literally say x is x. 00:04:34.920 --> 00:04:36.390 I want to plug in the value of x. 00:04:36.390 --> 00:04:40.020 So maybe the easiest way to do that is to surround it with curly braces. 00:04:40.020 --> 00:04:42.360 And then if I'm using these curly braces and I 00:04:42.360 --> 00:04:45.630 want Python to interpolate the value of that variable, 00:04:45.630 --> 00:04:49.440 that is substitute what x actually is in between those curly braces, 00:04:49.440 --> 00:04:52.170 recall that I need to use a format string or an F-string 00:04:52.170 --> 00:04:56.520 by fixing this whole thing with an F. Now that I've done that, let's go ahead 00:04:56.520 --> 00:04:57.640 and see what happens. 00:04:57.640 --> 00:05:02.010 I'm going to go ahead in my terminal window and run Python of number.py. 00:05:02.010 --> 00:05:02.760 I hit Enter. 00:05:02.760 --> 00:05:03.750 And so far, so good. 00:05:03.750 --> 00:05:05.580 All is well and being prompted for x. 00:05:05.580 --> 00:05:08.330 Let me go ahead and type in a number like 50. 00:05:08.330 --> 00:05:09.840 All right, that seems to work. 00:05:09.840 --> 00:05:12.610 Program seems to be correct. 00:05:12.610 --> 00:05:14.620 Or is it? 00:05:14.620 --> 00:05:19.610 What could go wrong in this program, even though nothing did just go wrong? 00:05:19.610 --> 00:05:22.630 But if I run it and run it and run it again, 00:05:22.630 --> 00:05:26.090 during the running of my program, what could still go wrong, 00:05:26.090 --> 00:05:28.660 especially if I'm not the human interacting with it 00:05:28.660 --> 00:05:30.910 but some other human instead? 00:05:30.910 --> 00:05:33.910 Any volunteers here for this one? 00:05:33.910 --> 00:05:35.780 What could go wrong? 00:05:35.780 --> 00:05:40.300 And in what way is this program not really correct, even 00:05:40.300 --> 00:05:42.530 though at first glance it seems so. 00:05:42.530 --> 00:05:44.170 AUDIENCE: [INAUDIBLE] 00:05:52.890 --> 00:05:54.990 DAVID MALAN: So I'm not calling an integer. 00:05:54.990 --> 00:05:56.532 I'm still having trouble hearing you. 00:05:56.532 --> 00:05:59.560 But what I think I heard is that if what the user types in is not, 00:05:59.560 --> 00:06:03.797 in fact, an integer, I can't just blindly convert it to an int. 00:06:03.797 --> 00:06:05.880 If I'm not putting too many words into your mouth, 00:06:05.880 --> 00:06:10.740 I think what I should perhaps do here is be a little defensive. 00:06:10.740 --> 00:06:14.040 And let me see if I can't simulate exactly the problem that 00:06:14.040 --> 00:06:14.920 could go wrong here. 00:06:14.920 --> 00:06:18.000 Let me go ahead and run, again, Python of number.py. 00:06:18.000 --> 00:06:19.290 Let me try another number. 00:06:19.290 --> 00:06:21.480 In fact, when testing your code, generally it's 00:06:21.480 --> 00:06:25.920 a good idea to test corner cases, maybe numbers that aren't quite as plain as 00:06:25.920 --> 00:06:27.907 or 49 or 51. 00:06:27.907 --> 00:06:30.990 Let's choose some numbers that might be a little more interesting, if only 00:06:30.990 --> 00:06:32.610 mathematically, like zero. 00:06:32.610 --> 00:06:34.050 All right, zero seems to work. 00:06:34.050 --> 00:06:35.880 My code still prints out that x is zero. 00:06:35.880 --> 00:06:37.890 What might be another corner case to consider? 00:06:37.890 --> 00:06:39.890 Well, let me go ahead and try a negative number. 00:06:39.890 --> 00:06:42.770 That, too, is pretty different in spirit from negative. 00:06:42.770 --> 00:06:43.680 Negative 1? 00:06:43.680 --> 00:06:44.880 OK, that works too. 00:06:44.880 --> 00:06:46.410 Well, let me try it one more time. 00:06:46.410 --> 00:06:48.990 I've tried positive numbers, negative numbers, 0. 00:06:48.990 --> 00:06:50.950 Let me try something like a cat. 00:06:50.950 --> 00:06:56.010 So literally, C-A-T-- typing in a string that doesn't even look like a number. 00:06:56.010 --> 00:06:58.950 And yet, let's see now what happens when I hit Enter. 00:06:58.950 --> 00:07:01.560 All right, we'll see now we've got another kind of error. 00:07:01.560 --> 00:07:05.310 It's not a syntax error, because I didn't make a typographical mistake. 00:07:05.310 --> 00:07:07.620 I didn't forget some piece of syntax. 00:07:07.620 --> 00:07:10.905 I actually now have an error with one of my values. 00:07:10.905 --> 00:07:12.780 And it's an a value I didn't even anticipate. 00:07:12.780 --> 00:07:17.200 The human, me, in this case typed it in long after I wrote the code. 00:07:17.200 --> 00:07:18.540 So what does this refer to? 00:07:18.540 --> 00:07:19.590 A value error. 00:07:19.590 --> 00:07:21.270 Well, let's see what the explanation is. 00:07:21.270 --> 00:07:25.375 Invalid literal for int with base 10, quote unquote, "cat." 00:07:25.375 --> 00:07:27.000 Now, this, too, is a bit of a mouthful. 00:07:27.000 --> 00:07:29.910 And, unfortunately, in Python and a lot of programming languages, 00:07:29.910 --> 00:07:32.817 the error messages are written for pretty comfortable programmers. 00:07:32.817 --> 00:07:35.650 And, of course, when you're learning programming for the first time, 00:07:35.650 --> 00:07:38.192 you might not be so comfortable with the programming language 00:07:38.192 --> 00:07:40.000 let alone the error messages. 00:07:40.000 --> 00:07:42.370 But let's see if we can't glean some insight. 00:07:42.370 --> 00:07:43.830 So invalid literal. 00:07:43.830 --> 00:07:47.410 Well, again, a literal is just something that's been typed in, it would seem, 00:07:47.410 --> 00:07:48.360 for int. 00:07:48.360 --> 00:07:50.220 What is int exactly? 00:07:50.220 --> 00:07:52.680 Well, int is the function I'm using to convert the user's 00:07:52.680 --> 00:07:55.200 input to a corresponding integer. 00:07:55.200 --> 00:07:58.260 Base 10, that refers to the decimal system, which is this 00:07:58.260 --> 00:07:59.970 the default that Python is using. 00:07:59.970 --> 00:08:02.460 And it looks like at the end of the day, what Python really 00:08:02.460 --> 00:08:07.570 doesn't like is that I passed cat, quote unquote, "to the int function." 00:08:07.570 --> 00:08:10.890 So how do I go about actually fixing this problem? 00:08:10.890 --> 00:08:13.862 Well, I could just add instructions in my program. 00:08:13.862 --> 00:08:15.570 Maybe I could add a line of print telling 00:08:15.570 --> 00:08:18.720 the user more explicitly, be sure to type an integer, 00:08:18.720 --> 00:08:20.220 or, please don't type cat. 00:08:20.220 --> 00:08:21.750 Please don't type strings. 00:08:21.750 --> 00:08:23.670 Of course, the user might still not oblige. 00:08:23.670 --> 00:08:25.420 They might not be reading the instruction. 00:08:25.420 --> 00:08:27.600 So that too is probably not an effective strategy. 00:08:27.600 --> 00:08:31.278 What we really want to do is write our code with error handling in mind. 00:08:31.278 --> 00:08:33.570 We want to write lines of code that not only accomplish 00:08:33.570 --> 00:08:36.539 the problems we care about but that also handle 00:08:36.539 --> 00:08:39.299 errors that might unexpectedly happen. 00:08:39.299 --> 00:08:41.970 And, in general, when programming, programming defensively. 00:08:41.970 --> 00:08:44.910 Assume that the users aren't going to be paying attention or, worse, 00:08:44.910 --> 00:08:45.850 they're malicious. 00:08:45.850 --> 00:08:47.920 They're trying to crash your program. 00:08:47.920 --> 00:08:50.280 So we want to handle as many errors as we can. 00:08:50.280 --> 00:08:52.470 Now, how do we go about doing that in Python? 00:08:52.470 --> 00:08:56.850 Well, it turns out whether you want to catch a value error or other types 00:08:56.850 --> 00:08:59.250 of errors as well-- though not syntax error-- 00:08:59.250 --> 00:09:01.620 Python actually has this keyword called try. 00:09:01.620 --> 00:09:02.910 And it's sort of aptly named. 00:09:02.910 --> 00:09:05.700 If you want to try to do something in Python, 00:09:05.700 --> 00:09:07.680 you can literally use this keyword. 00:09:07.680 --> 00:09:11.430 And you can check whether or not something exceptional, something 00:09:11.430 --> 00:09:12.840 erroneous, has happened. 00:09:12.840 --> 00:09:16.140 So using both try and this other keyword, except, 00:09:16.140 --> 00:09:20.400 can I go and try to do something except if something goes wrong? 00:09:20.400 --> 00:09:22.510 I can do something else instead. 00:09:22.510 --> 00:09:25.020 So let's consider, how can I go about trying 00:09:25.020 --> 00:09:29.010 to convert the user's input to an int except if something goes wrong? 00:09:29.010 --> 00:09:31.200 Well, let me go back to my code here. 00:09:31.200 --> 00:09:34.750 And let me propose that I now modify this example as follows. 00:09:34.750 --> 00:09:37.320 Let me go ahead and, above my first line of code, 00:09:37.320 --> 00:09:40.500 I literally write, try and a colon, telling Python, 00:09:40.500 --> 00:09:42.160 try to do the following. 00:09:42.160 --> 00:09:44.700 I'm going to go ahead and indent my existing lines of codes 00:09:44.700 --> 00:09:47.770 here by the same number of spaces, four in this case. 00:09:47.770 --> 00:09:51.060 And then I'm going to add one more new line down here that literally says, 00:09:51.060 --> 00:09:53.352 except Value Error. 00:09:53.352 --> 00:09:55.560 And notice it's important that I've capitalized the V 00:09:55.560 --> 00:09:59.460 and I've capitalized the E. These symbols are case sensitive. 00:09:59.460 --> 00:10:02.730 And this is now an opportunity, after this colon, 00:10:02.730 --> 00:10:07.230 to tell Python what I want to do in exceptional cases, when 00:10:07.230 --> 00:10:10.920 the number or the input from the user is not, in fact, a number. 00:10:10.920 --> 00:10:13.860 And I'm going to say something plain like print, quote unquote, 00:10:13.860 --> 00:10:15.750 "x is not an integer." 00:10:15.750 --> 00:10:19.750 I'm at least going to tell the user roughly what the problem actually is. 00:10:19.750 --> 00:10:21.030 So notice another detail. 00:10:21.030 --> 00:10:22.620 The indentation is important. 00:10:22.620 --> 00:10:26.970 Because I have try on line one and I've indented lines two and three, those 00:10:26.970 --> 00:10:30.990 are the two lines of code that I'm trying, except if I see a value error, 00:10:30.990 --> 00:10:33.630 line five, because it's indented is what is 00:10:33.630 --> 00:10:36.790 going to get executed in cases of those errors. 00:10:36.790 --> 00:10:43.920 Let me go ahead now back to my terminal window and run Python of number.py, 00:10:43.920 --> 00:10:44.490 Enter. 00:10:44.490 --> 00:10:47.130 And let's go ahead and type in again. 00:10:47.130 --> 00:10:48.270 Still seems to work. 00:10:48.270 --> 00:10:50.302 And, of course, I'm trying and succeeding. 00:10:50.302 --> 00:10:53.260 Let me go ahead and try once more, this time, though, with the word cat 00:10:53.260 --> 00:10:55.450 or, really, anything that's not a decimal number. 00:10:55.450 --> 00:10:59.680 And now you'll see much more cleanly x is not an integer. 00:10:59.680 --> 00:11:02.350 I'm not seeing some scary error message that I, the user, 00:11:02.350 --> 00:11:04.330 am going to have no idea how to handle. 00:11:04.330 --> 00:11:06.640 Now you, the programmer, have anticipated 00:11:06.640 --> 00:11:08.290 that something exceptional can happen. 00:11:08.290 --> 00:11:12.850 And you've gone about actually handling the error for the user, 00:11:12.850 --> 00:11:15.490 giving them an appropriate error message instead. 00:11:15.490 --> 00:11:18.340 Let me pause here and see, are there any questions now 00:11:18.340 --> 00:11:21.190 on what we've just done by introducing try 00:11:21.190 --> 00:11:25.370 and accept to handle this value error? 00:11:25.370 --> 00:11:28.380 AUDIENCE: Is value ever the only type of error you can get? 00:11:28.380 --> 00:11:29.610 Or are there other types? 00:11:29.610 --> 00:11:31.380 DAVID MALAN: Is value error the only thing you can catch? 00:11:31.380 --> 00:11:32.590 There are other errors as well. 00:11:32.590 --> 00:11:33.930 And we'll see a few of them today. 00:11:33.930 --> 00:11:36.270 And there's many, many more, honestly, that if you continue 00:11:36.270 --> 00:11:38.145 programming and programming in Python, you're 00:11:38.145 --> 00:11:41.710 going to see a lot of them over the weeks the months the years to come. 00:11:41.710 --> 00:11:43.830 But the technique for handling them is going 00:11:43.830 --> 00:11:47.490 to be largely the same other questions on try, accept, 00:11:47.490 --> 00:11:49.260 or these exceptions more generally? 00:11:49.260 --> 00:11:51.210 AUDIENCE: Yes, sir. 00:11:51.210 --> 00:11:55.980 Actually, to use the except block, you need to know the type of error, right? 00:11:55.980 --> 00:12:01.150 [INAUDIBLE] what if you can't anticipate this particular type of error? 00:12:01.150 --> 00:12:02.650 DAVID MALAN: A really good question. 00:12:02.650 --> 00:12:06.330 So I'm being very good about catching, so to speak, 00:12:06.330 --> 00:12:08.793 the very error that I might happen. 00:12:08.793 --> 00:12:10.710 I don't know when it might happen because it's 00:12:10.710 --> 00:12:11.877 going to depend on the user. 00:12:11.877 --> 00:12:15.180 But I know what kind of error will happen from the int function. 00:12:15.180 --> 00:12:19.590 There is a way in Python where you can say, except if anything goes wrong. 00:12:19.590 --> 00:12:23.440 And you can literally omit value error and just catch everything. 00:12:23.440 --> 00:12:27.660 The problem with that is that it sometimes hides other bugs in your code 00:12:27.660 --> 00:12:29.952 because you don't necessarily know what's going wrong. 00:12:29.952 --> 00:12:32.160 And if you don't necessarily know what's going wrong, 00:12:32.160 --> 00:12:34.300 how can you possibly handle it correctly? 00:12:34.300 --> 00:12:35.490 So bad practice. 00:12:35.490 --> 00:12:38.940 And it put another way, it's lazy to do that, to just say, catch everything 00:12:38.940 --> 00:12:40.140 and I'll deal with it here. 00:12:40.140 --> 00:12:43.740 So a much better practice would be to figure out what kind of errors 00:12:43.740 --> 00:12:48.210 could happen and include mention of them explicitly, as I have done. 00:12:48.210 --> 00:12:51.390 Now, with that said, if you read Python's official documentation, 00:12:51.390 --> 00:12:54.120 as you'll eventually invariably do, it is not 00:12:54.120 --> 00:12:58.080 great about telling you proactively what kinds of errors 00:12:58.080 --> 00:13:00.390 can be raised in this way. 00:13:00.390 --> 00:13:03.270 So it's a bit of contradictory advice. 00:13:03.270 --> 00:13:04.620 You should do it this way. 00:13:04.620 --> 00:13:07.470 But it's not always obvious what you should be checking for. 00:13:07.470 --> 00:13:09.420 But you get better at it with practice. 00:13:09.420 --> 00:13:12.760 And some of the times, the documentation does spell out what could go wrong. 00:13:12.760 --> 00:13:14.610 Let me turn our attention now back to this 00:13:14.610 --> 00:13:17.790 and point out that even though this is better code, 00:13:17.790 --> 00:13:21.450 it is more correct in the sense that I'm not just leaving it to the user 00:13:21.450 --> 00:13:25.410 to see some really ugly default Python error message that most people are 00:13:25.410 --> 00:13:27.600 going to have no idea what to do with, I'm 00:13:27.600 --> 00:13:29.100 at least handling it more elegantly. 00:13:29.100 --> 00:13:31.570 And I'm printing out x is not an integer. 00:13:31.570 --> 00:13:33.000 So it's at least more instructive. 00:13:33.000 --> 00:13:36.150 But this isn't necessarily the best way to implement this code. 00:13:36.150 --> 00:13:36.720 Why? 00:13:36.720 --> 00:13:39.780 Well, here, too, I'm actually still being a little lazy. 00:13:39.780 --> 00:13:44.190 So notice that I'm trying to do not one line of code but two lines of code. 00:13:44.190 --> 00:13:47.820 And this isn't a huge deal because we're only talking about two lines of code. 00:13:47.820 --> 00:13:51.000 But in the interest of preaching best practices, 00:13:51.000 --> 00:13:56.940 you should really only be trying to do the one or very few lines of code that 00:13:56.940 --> 00:14:01.740 can actually raise an exception that can actually fail in some way. 00:14:01.740 --> 00:14:06.900 I am pretty sure that calling print here is not going to raise a value error. 00:14:06.900 --> 00:14:10.740 Whether x is an int or a string or a float or anything else, 00:14:10.740 --> 00:14:15.010 the format string feature of Python is going to handle printing it just fine. 00:14:15.010 --> 00:14:17.290 So, really, what I'm going to do is this. 00:14:17.290 --> 00:14:21.420 I'm going to move this line three down to the bottom of my code. 00:14:21.420 --> 00:14:22.830 I no longer need to indent it. 00:14:22.830 --> 00:14:26.460 I'm just going to execute it at the bottom of my file here. 00:14:26.460 --> 00:14:28.710 Unfortunately, by doing this-- 00:14:28.710 --> 00:14:32.610 I've done a good thing by now only trying to do the minimal amount of work 00:14:32.610 --> 00:14:36.450 necessary that might raise the exception of value error. 00:14:36.450 --> 00:14:38.873 But I fear I've introduced a new mistake. 00:14:38.873 --> 00:14:39.540 Well, let's see. 00:14:39.540 --> 00:14:40.950 What is now incorrect? 00:14:40.950 --> 00:14:44.490 Let me go ahead and again run Python of number.py, Enter. 00:14:44.490 --> 00:14:46.755 Let me go ahead and do it correctly with 50. 00:14:46.755 --> 00:14:48.340 And all seems to be well. 00:14:48.340 --> 00:14:50.190 But, again, let's try those corner cases-- 00:14:50.190 --> 00:14:52.920 the zeros, the negative numbers, or, in this case, the cat. 00:14:52.920 --> 00:14:55.230 Let me go ahead and type in C-A-T again. 00:14:55.230 --> 00:14:55.950 Enter. 00:14:55.950 --> 00:14:57.610 Now I have a name error. 00:14:57.610 --> 00:15:01.350 So now it's yet another type of error in my code that I've introduced here. 00:15:01.350 --> 00:15:03.180 And what does this name error mean? 00:15:03.180 --> 00:15:07.140 Well, just as a value error refers to that-- the value of some variable, 00:15:07.140 --> 00:15:09.240 the value that someone has typed in is incorrect-- 00:15:09.240 --> 00:15:13.500 name error tends to refer to your code, like you're doing something with 00:15:13.500 --> 00:15:16.350 the name of a variable that you shouldn't. 00:15:16.350 --> 00:15:17.350 And why might that be? 00:15:17.350 --> 00:15:19.350 Well, let me turn our attention back to the code 00:15:19.350 --> 00:15:22.500 here and consider, what is it complaining about? 00:15:22.500 --> 00:15:24.630 Well, the name errors what I see down here. 00:15:24.630 --> 00:15:28.710 And it's telling me, name, quote unquote, "x is not defined." 00:15:28.710 --> 00:15:31.950 And notice if I look further here, it is mentioning line six. 00:15:31.950 --> 00:15:35.610 So I know the problem is with my code on line six. 00:15:35.610 --> 00:15:38.460 And that worked a moment ago. 00:15:38.460 --> 00:15:42.210 And I'm defining x on line two. 00:15:42.210 --> 00:15:48.750 But let me ask the group here, why does x, in fact, exist online six? 00:15:48.750 --> 00:15:52.200 Why is it not defined, even though I'm pretty sure I 00:15:52.200 --> 00:15:54.920 was intending to define it on line two? 00:15:54.920 --> 00:16:00.330 AUDIENCE: Maybe the scope of the variable is between the [INAUDIBLE].. 00:16:00.330 --> 00:16:02.130 DAVID MALAN: So, good terminology. 00:16:02.130 --> 00:16:06.270 Scope refers to the portion of code in which a variable exists. 00:16:06.270 --> 00:16:08.340 That, too, though isn't quite right in Python. 00:16:08.340 --> 00:16:12.990 That would be true in C, C++, and Java, where indentation or curly braces tend 00:16:12.990 --> 00:16:15.120 to define the scope of a variable. 00:16:15.120 --> 00:16:16.770 But, again, here in general-- 00:16:16.770 --> 00:16:18.420 and this worked a moment ago. 00:16:18.420 --> 00:16:22.110 X exists once it's defined on line two because, remember, 00:16:22.110 --> 00:16:24.630 I printed out x is 50 a little bit ago. 00:16:24.630 --> 00:16:27.990 Let's try one more hypothesis here. 00:16:27.990 --> 00:16:29.760 One more hand? 00:16:29.760 --> 00:16:32.970 Why is x somehow still not defined? 00:16:32.970 --> 00:16:36.400 AUDIENCE: Yeah, so is it because it's local variable, 00:16:36.400 --> 00:16:39.320 meaning that it doesn't define outside of the scope 00:16:39.320 --> 00:16:42.570 because what people have mentioned. 00:16:42.570 --> 00:16:45.150 It prompts the input in try, right? 00:16:45.150 --> 00:16:46.818 The outside of it is undefined. 00:16:46.818 --> 00:16:48.360 DAVID MALAN: So still good instincts. 00:16:48.360 --> 00:16:49.710 And good terminology, too. 00:16:49.710 --> 00:16:52.800 There's this notion of local variables, which tend to exist inside 00:16:52.800 --> 00:16:55.080 of functions, for instance, global variables, 00:16:55.080 --> 00:16:57.150 which tend to exist in entire files. 00:16:57.150 --> 00:16:59.860 In this case, too, though, that's not quite the case. 00:16:59.860 --> 00:17:03.060 What's happening here boils down to order of operations. 00:17:03.060 --> 00:17:06.060 Let me come back to the code here and recall that any time we've 00:17:06.060 --> 00:17:09.510 discussed the assignment operator, the single equal sign, that copies 00:17:09.510 --> 00:17:11.280 a value from the right to the left. 00:17:11.280 --> 00:17:14.670 But consider for a moment at what point something is going wrong. 00:17:14.670 --> 00:17:17.819 Well, the input function is probably working just fine 00:17:17.819 --> 00:17:20.310 because we've used that a lot now to get users' input. 00:17:20.310 --> 00:17:24.150 It always returns a string or a stir in Python. 00:17:24.150 --> 00:17:25.650 But what could be going wrong? 00:17:25.650 --> 00:17:32.310 Well, if I'm passing that string to the int function as its argument, 00:17:32.310 --> 00:17:34.920 it's probably the int's function that's erroring. 00:17:34.920 --> 00:17:37.830 And, indeed, if you think back earlier when we had the value error, 00:17:37.830 --> 00:17:39.930 it was, in fact, the int function that did not 00:17:39.930 --> 00:17:42.520 like, quote unquote, "cat" as input. 00:17:42.520 --> 00:17:45.420 So this is all to say that this portion of my code 00:17:45.420 --> 00:17:48.870 highlighted now to the right of the equal sign, that's 00:17:48.870 --> 00:17:50.700 the code that's creating a problem. 00:17:50.700 --> 00:17:53.410 That's the code that was creating a value error. 00:17:53.410 --> 00:17:57.000 And in this case, we're catching the value error. 00:17:57.000 --> 00:18:01.170 But because the value error is happening on the right of the equal sign, 00:18:01.170 --> 00:18:03.780 there's no value being copied to the left. 00:18:03.780 --> 00:18:06.370 The error is interrupting that whole process. 00:18:06.370 --> 00:18:10.530 So even though we see x equals dot dot dot on line two, 00:18:10.530 --> 00:18:13.200 the portion of that line to the left of the equal sign 00:18:13.200 --> 00:18:16.140 isn't getting evaluated, ultimately, because the value 00:18:16.140 --> 00:18:18.300 error is happening too soon. 00:18:18.300 --> 00:18:20.988 And so when we finally get down to line six, 00:18:20.988 --> 00:18:23.280 even though it looked like I was defining on line two-- 00:18:23.280 --> 00:18:26.160 and I would have defined x on line two if all had gone well-- 00:18:26.160 --> 00:18:29.470 we didn't get to the part where the value is copied from right to left 00:18:29.470 --> 00:18:31.570 because the value error happened first. 00:18:31.570 --> 00:18:34.350 So this code is just incorrect now. 00:18:34.350 --> 00:18:37.090 So how do I go about solving something like this? 00:18:37.090 --> 00:18:41.190 Well, it turns out that there's another feature of the try 00:18:41.190 --> 00:18:43.650 and accept syntax that Python supports, which is 00:18:43.650 --> 00:18:46.260 that it also supports the keyword else. 00:18:46.260 --> 00:18:47.970 Now, we've seen else before. 00:18:47.970 --> 00:18:51.000 If you think back to our discussion of conditionals, we saw if. 00:18:51.000 --> 00:18:52.290 We saw elif. 00:18:52.290 --> 00:18:55.260 We saw else, which was kind of this catchall, what 00:18:55.260 --> 00:18:58.200 you should do in the event that nothing else is relevant. 00:18:58.200 --> 00:19:02.760 That's kind of the same intuition here for the try-except feature of Python. 00:19:02.760 --> 00:19:04.560 What you can do is this. 00:19:04.560 --> 00:19:09.450 You can try to do the following, as I've done, except if this goes wrong. 00:19:09.450 --> 00:19:13.420 But if nothing goes wrong, else go ahead and do this. 00:19:13.420 --> 00:19:16.620 So this is one way I can solve this same problem now. 00:19:16.620 --> 00:19:21.030 No matter what now, Python is going to try to execute line two. 00:19:21.030 --> 00:19:24.030 If something goes wrong, it's going to execute lines three 00:19:24.030 --> 00:19:26.500 and four to handle that value error. 00:19:26.500 --> 00:19:30.340 However, if you try and this code succeeds, 00:19:30.340 --> 00:19:32.880 then there is no exception to handle. 00:19:32.880 --> 00:19:35.697 So you're then going to execute this line here. 00:19:35.697 --> 00:19:37.530 So it's a little confusing, perhaps, in that 00:19:37.530 --> 00:19:41.430 we're now using else both for conditionals-- if, elif, elif, elif, 00:19:41.430 --> 00:19:42.060 else. 00:19:42.060 --> 00:19:45.840 And we're also using else with these try-except blocks. 00:19:45.840 --> 00:19:46.690 But that's OK. 00:19:46.690 --> 00:19:47.580 That's part of the language. 00:19:47.580 --> 00:19:48.705 That's one of the features. 00:19:48.705 --> 00:19:54.330 So now if I rerun this code in my terminal window, Python of number.py-- 00:19:54.330 --> 00:19:56.010 let's do something correct, like 50-- 00:19:56.010 --> 00:19:58.530 I see that x is 50. 00:19:58.530 --> 00:20:00.420 So line one is executed. 00:20:00.420 --> 00:20:01.890 We're trying to do the following. 00:20:01.890 --> 00:20:05.340 Line two is executed because the conversion happened successfully 00:20:05.340 --> 00:20:07.950 and the number 50 gets copied from right to left. 00:20:07.950 --> 00:20:10.030 The exception does not happen. 00:20:10.030 --> 00:20:11.670 So we ignore lines three and four. 00:20:11.670 --> 00:20:16.110 We jump immediately to line five and six, which prints out the result. 00:20:16.110 --> 00:20:18.810 By contrast, though-- let's do this one last time. 00:20:18.810 --> 00:20:23.160 Python of number.py-- let's type in cat or, again, any other word and hit Enter 00:20:23.160 --> 00:20:23.700 now. 00:20:23.700 --> 00:20:25.380 We don't see what x is. 00:20:25.380 --> 00:20:29.380 Rather, we see, quote unquote, "x is not an integer," 00:20:29.380 --> 00:20:33.030 which is what's being handled in my except clause. 00:20:33.030 --> 00:20:35.880 All right, let me pause here because that's a lot of new syntax, 00:20:35.880 --> 00:20:39.510 and see here if there's any questions on try, on except, 00:20:39.510 --> 00:20:42.870 on else, name error, or value error. 00:20:42.870 --> 00:20:45.792 AUDIENCE: Can you please repeat the try function? 00:20:45.792 --> 00:20:47.250 DAVID MALAN: Repeat the name error? 00:20:47.250 --> 00:20:48.870 What's the problem with the name error? 00:20:48.870 --> 00:20:49.200 AUDIENCE: Yes. 00:20:49.200 --> 00:20:49.500 Yes. 00:20:49.500 --> 00:20:50.208 DAVID MALAN: Yes. 00:20:50.208 --> 00:20:52.710 So let's just rewind a couple of lines here 00:20:52.710 --> 00:20:55.890 before I fix this problem by now getting rid of the else. 00:20:55.890 --> 00:21:00.360 A moment ago, we had code that looked like this, whereby 00:21:00.360 --> 00:21:03.780 I was getting a name error, Python of number.py, Enter, 00:21:03.780 --> 00:21:07.710 typing in cat, that looked like this, where name x is not defined. 00:21:07.710 --> 00:21:11.700 And the problem was on line six, according to this output in Python. 00:21:11.700 --> 00:21:13.798 Well, let's think about this now deductively. 00:21:13.798 --> 00:21:15.090 Let's try a different approach. 00:21:15.090 --> 00:21:18.660 On line six, I'm seeing an error that name x is not defined. 00:21:18.660 --> 00:21:22.150 OK, Python's already telling me x does not exist at that point. 00:21:22.150 --> 00:21:23.820 So how could that possibly be? 00:21:23.820 --> 00:21:26.340 Well, where should x be defined? 00:21:26.340 --> 00:21:29.940 Well, presumably, x is defined on line two, up here. 00:21:29.940 --> 00:21:31.440 So what could go wrong? 00:21:31.440 --> 00:21:35.210 Well, if the user has inputted something that doesn't look like a number, 00:21:35.210 --> 00:21:40.220 like the word cat, passing cat, the return value of input, 00:21:40.220 --> 00:21:45.810 as the argument to int to convert the word to an int makes no sense. 00:21:45.810 --> 00:21:49.550 You can't convert a cat, C-A-T, to an integer at all. 00:21:49.550 --> 00:21:55.370 So the int function is raising a value error at that point. 00:21:55.370 --> 00:21:58.770 And the error is being handled with this code here. 00:21:58.770 --> 00:22:02.150 But notice this line six is not indented. 00:22:02.150 --> 00:22:06.500 It's left aligned with the rest of my code, which means no matter what, 00:22:06.500 --> 00:22:08.240 line six is going to execute. 00:22:08.240 --> 00:22:12.020 It's going to execute whether I typed in 50 or I typed in cat. 00:22:12.020 --> 00:22:15.540 But if I typed in cat, again, x never gets a value. 00:22:15.540 --> 00:22:17.990 So it's not defined here on line six. 00:22:17.990 --> 00:22:21.080 So when I introduced, finally, the else statement, that 00:22:21.080 --> 00:22:23.700 makes sure that these things are mutually exclusive. 00:22:23.700 --> 00:22:29.990 I only execute the else if I tried and succeeded up above. 00:22:29.990 --> 00:22:35.390 Well, let me propose that we refine this just a little bit further as well 00:22:35.390 --> 00:22:39.380 and consider how we might improve this example a little bit more. 00:22:39.380 --> 00:22:45.950 It's a little unfriendly of me to be rejecting the user's input after they 00:22:45.950 --> 00:22:49.220 fail to provide an integer and just quitting the program, really, right? 00:22:49.220 --> 00:22:51.950 It'd be more user friendly if I just prompt 00:22:51.950 --> 00:22:54.350 or reprompt the user again and again. 00:22:54.350 --> 00:22:58.310 And in the chat, if you could, what's the feature of Python 00:22:58.310 --> 00:23:01.340 that you can use if you want to do something again and again 00:23:01.340 --> 00:23:04.970 and again until such time as the user cooperates and gives you 00:23:04.970 --> 00:23:07.370 what you're looking for, like a number? 00:23:07.370 --> 00:23:09.120 So yeah, loop, loop, loop. 00:23:09.120 --> 00:23:12.360 So a loop is something that happens again and again and again. 00:23:12.360 --> 00:23:15.920 And maybe we can use that same mechanism, a loop, in order 00:23:15.920 --> 00:23:17.300 to prompt the user for x. 00:23:17.300 --> 00:23:19.635 And if they don't give us a number, prompt them again. 00:23:19.635 --> 00:23:22.010 And if they don't, prompt them again and again and again. 00:23:22.010 --> 00:23:24.060 We don't need to just quit out of the program. 00:23:24.060 --> 00:23:26.120 So, quickly-- so let me propose this. 00:23:26.120 --> 00:23:30.590 Let me propose here that I improve this code by deliberately doing this. 00:23:30.590 --> 00:23:36.380 Let me induce a infinite loop at the very top of my code with while true. 00:23:36.380 --> 00:23:40.400 Recall that the wild keyword induces a loop, a cycle that behaves like this. 00:23:40.400 --> 00:23:42.920 And it asks a question, a Boolean expression 00:23:42.920 --> 00:23:45.420 that needs to evaluate either to true or false. 00:23:45.420 --> 00:23:47.300 Well, if I want this thing to loop forever, 00:23:47.300 --> 00:23:51.502 at least initially, we'll just say while true because true is true. 00:23:51.502 --> 00:23:53.210 So this has the effect of doing something 00:23:53.210 --> 00:23:56.600 no matter what forever unless we break out of it early. 00:23:56.600 --> 00:23:58.980 Now I'm going to go ahead and do this. 00:23:58.980 --> 00:24:02.420 I'm going to go ahead and move my try except code 00:24:02.420 --> 00:24:06.740 indented underneath this loop so that I'm trying to get an x. 00:24:06.740 --> 00:24:11.120 If I have a value error instead, I print out x is not an integer. 00:24:11.120 --> 00:24:15.230 But this time, what do I want to do if the user does 00:24:15.230 --> 00:24:18.680 try and succeed in giving me a number? 00:24:18.680 --> 00:24:20.100 Well, I can do this. 00:24:20.100 --> 00:24:22.400 I can just break out of my code here. 00:24:22.400 --> 00:24:25.160 And down here now, I can use that same line of code 00:24:25.160 --> 00:24:31.130 from before, an F-string that says x is, and then in curly braces, x again. 00:24:31.130 --> 00:24:32.910 So what's going on here? 00:24:32.910 --> 00:24:35.270 I think this code now, because I've added 00:24:35.270 --> 00:24:39.350 the loop, is going to have the effect of trying at least once, maybe 00:24:39.350 --> 00:24:44.360 a second time, maybe a third time maybe 500 times until the user finally gives 00:24:44.360 --> 00:24:46.610 me what I want, which is an integer. 00:24:46.610 --> 00:24:50.000 And once they do, once there's no value error happening, 00:24:50.000 --> 00:24:51.860 then I break out of the loop. 00:24:51.860 --> 00:24:54.350 And line nine executes as I would hope. 00:24:54.350 --> 00:24:56.540 So let me go ahead and try executing this version-- 00:24:56.540 --> 00:24:58.970 Python of number.py, Enter. 00:24:58.970 --> 00:24:59.990 What's x? 00:24:59.990 --> 00:25:02.090 Let me go ahead and type in the easy thing first-- 00:25:02.090 --> 00:25:03.210 50. 00:25:03.210 --> 00:25:03.710 X is 50. 00:25:03.710 --> 00:25:06.680 What just happened in terms of the control flow 00:25:06.680 --> 00:25:08.780 of this program, the flow of my logic? 00:25:08.780 --> 00:25:11.750 Well, I first found myself on line one inside of a loop. 00:25:11.750 --> 00:25:13.370 Hopefully, I'll get out of this loop. 00:25:13.370 --> 00:25:14.390 What did I then do? 00:25:14.390 --> 00:25:18.080 On lines two and three, I tried to get input from the user 00:25:18.080 --> 00:25:19.160 and convert it to an int. 00:25:19.160 --> 00:25:20.900 Well, I was a nice guy this time. 00:25:20.900 --> 00:25:23.390 And I typed in 50, which looks like and is a number. 00:25:23.390 --> 00:25:25.250 So the int function converted it just fine 00:25:25.250 --> 00:25:28.280 and stored it from right to left in x. 00:25:28.280 --> 00:25:29.390 Except value error? 00:25:29.390 --> 00:25:31.760 There is no value error because if I typed in a number, 00:25:31.760 --> 00:25:33.410 there's nothing exceptional happening. 00:25:33.410 --> 00:25:36.930 This is a boring, good execution of my program. 00:25:36.930 --> 00:25:38.120 So what happens? 00:25:38.120 --> 00:25:39.810 I break out of the loop. 00:25:39.810 --> 00:25:44.780 So, again, the else clause is associated with the try not with the except. 00:25:44.780 --> 00:25:47.990 And once I'm out of the loop, of course, I'm just printing out what x is. 00:25:47.990 --> 00:25:50.480 Well, let's try the other scenario that might happen. 00:25:50.480 --> 00:25:52.730 Python of number.py, Enter. 00:25:52.730 --> 00:25:53.390 What's x? 00:25:53.390 --> 00:25:55.400 Let's try cat or any other word. 00:25:55.400 --> 00:25:56.810 Enter. 00:25:56.810 --> 00:25:59.510 Ah, this is now a new feature. 00:25:59.510 --> 00:26:01.610 I'm being informed what I did wrong. 00:26:01.610 --> 00:26:02.790 X is not an integer. 00:26:02.790 --> 00:26:05.120 So I'm getting some useful user feedback. 00:26:05.120 --> 00:26:07.520 But notice, again, I'm prompted, what's x? 00:26:07.520 --> 00:26:09.860 Well, let me try typing in dog. 00:26:09.860 --> 00:26:11.040 X is not an integer. 00:26:11.040 --> 00:26:11.750 What's x? 00:26:11.750 --> 00:26:13.100 Let me try bird. 00:26:13.100 --> 00:26:14.210 Enter. 00:26:14.210 --> 00:26:15.330 X is not an integer. 00:26:15.330 --> 00:26:15.830 What's x? 00:26:15.830 --> 00:26:19.850 And suffice it to say, this will happen now forever if I'm in an infinite loop 00:26:19.850 --> 00:26:23.768 until I try and succeed, at which point I break out. 00:26:23.768 --> 00:26:24.560 So let's try again. 00:26:24.560 --> 00:26:25.480 50, Enter. 00:26:25.480 --> 00:26:26.980 Now I'm out of the loop. 00:26:26.980 --> 00:26:30.530 And I'm printing out what x actually is. 00:26:30.530 --> 00:26:33.970 All right, let me pause here and see if there are any questions. 00:26:33.970 --> 00:26:35.560 The logic is almost the same. 00:26:35.560 --> 00:26:38.080 But what is different now is I'm in a loop. 00:26:38.080 --> 00:26:40.870 And I'm using the keyword break in Python 00:26:40.870 --> 00:26:43.510 to deliberately break out of the loop when I'm 00:26:43.510 --> 00:26:46.540 ready to, once the user has cooperated. 00:26:46.540 --> 00:26:48.910 AUDIENCE: Do we really need to break? 00:26:48.910 --> 00:26:51.130 Can't we just print? 00:26:51.130 --> 00:26:54.235 Or what keeps us from just printing? 00:26:54.235 --> 00:26:55.360 DAVID MALAN: Good question. 00:26:55.360 --> 00:26:56.290 So let me try that. 00:26:56.290 --> 00:26:57.490 Couldn't I just print? 00:26:57.490 --> 00:26:59.240 Well, let's see what happens if I do that. 00:26:59.240 --> 00:27:02.710 Let me move this print line at the end into my loop 00:27:02.710 --> 00:27:04.380 here, thereby shortening the program. 00:27:04.380 --> 00:27:06.130 And, in general, that's been a good thing. 00:27:06.130 --> 00:27:08.410 Python of number.py, Enter. 00:27:08.410 --> 00:27:10.530 Let me go ahead and type in 50. 00:27:10.530 --> 00:27:11.410 OK, x is 50. 00:27:11.410 --> 00:27:13.105 What's x? 00:27:13.105 --> 00:27:14.395 OK, maybe it's 49. 00:27:14.395 --> 00:27:15.700 X is 49. 00:27:15.700 --> 00:27:17.320 OK, maybe 48. 00:27:17.320 --> 00:27:19.030 Unfortunately, I think-- you're laughing. 00:27:19.030 --> 00:27:19.530 You see it. 00:27:19.530 --> 00:27:22.115 I never break out of the loop, which maybe that's a feature. 00:27:22.115 --> 00:27:23.740 Maybe you want this to be your program. 00:27:23.740 --> 00:27:24.282 But I didn't. 00:27:24.282 --> 00:27:25.870 I'd eventually like this game to stop. 00:27:25.870 --> 00:27:28.150 So I need to break out in that way. 00:27:28.150 --> 00:27:29.890 But I can do it a little differently. 00:27:29.890 --> 00:27:33.200 And let me propose that we modify this a little bit. 00:27:33.200 --> 00:27:36.130 But, first, any other questions on this syntax here? 00:27:36.130 --> 00:27:41.302 Let me rewind to the prior version. 00:27:41.302 --> 00:27:46.870 AUDIENCE: Hi, can I use a break [INAUDIBLE] except and else? 00:27:46.870 --> 00:27:51.700 For example, in another print, may you use printing the else, 00:27:51.700 --> 00:27:55.760 you can use prints together with break or something like this? 00:27:55.760 --> 00:27:59.110 DAVID MALAN: So you can use break inside of loops to break out of loops. 00:27:59.110 --> 00:28:01.450 And you can use it inside of a conditional, 00:28:01.450 --> 00:28:03.610 like an if, an elif, or an else. 00:28:03.610 --> 00:28:06.940 You can do it inside of a try, except, else statement to. 00:28:06.940 --> 00:28:09.190 Any time you're in a loop that you want to break out 00:28:09.190 --> 00:28:11.110 of, you can use this keyword, break. 00:28:11.110 --> 00:28:13.120 I'm using it in the context of exceptions. 00:28:13.120 --> 00:28:14.538 But it's not restricted to that. 00:28:14.538 --> 00:28:15.580 And let me show you, too. 00:28:15.580 --> 00:28:17.205 It doesn't even have to be in the else. 00:28:17.205 --> 00:28:20.140 If I wanted to, I could actually do this. 00:28:20.140 --> 00:28:21.940 I could get rid of my else. 00:28:21.940 --> 00:28:26.170 And I could go back to line three, add another line that's indented, 00:28:26.170 --> 00:28:28.910 line four, and break out here. 00:28:28.910 --> 00:28:31.450 Now, why is this logically OK? 00:28:31.450 --> 00:28:34.610 Well, consider what I'm now trying to do. 00:28:34.610 --> 00:28:38.890 I'm trying to execute line three and converting the user's input to an int. 00:28:38.890 --> 00:28:42.910 And I'm trying to store the result from right to left in x. 00:28:42.910 --> 00:28:45.700 If something goes wrong, the code we've already seen 00:28:45.700 --> 00:28:48.670 is immediately going to jump to line five 00:28:48.670 --> 00:28:51.740 and then six to handle the exception. 00:28:51.740 --> 00:28:54.430 But if nothing goes wrong, my code presumably 00:28:54.430 --> 00:28:57.410 should just keep on executing line by line. 00:28:57.410 --> 00:29:00.170 So I could technically logically put the break here. 00:29:00.170 --> 00:29:02.290 And watch what happens when I run this version. 00:29:02.290 --> 00:29:06.520 Python of number.py, 50, Enter, it worked. 00:29:06.520 --> 00:29:08.050 I broke out of the loop. 00:29:08.050 --> 00:29:09.760 Now, which way is better? 00:29:09.760 --> 00:29:12.460 Honestly, I think it could go either way at this point. 00:29:12.460 --> 00:29:15.100 This program is so relatively short that even 00:29:15.100 --> 00:29:18.760 though I'm trying to do two things now, one of which, the break, 00:29:18.760 --> 00:29:19.870 is not going to fail. 00:29:19.870 --> 00:29:21.273 You either break or you don't. 00:29:21.273 --> 00:29:24.190 There's no piece of data from the user that's going to influence that. 00:29:24.190 --> 00:29:27.310 We don't strictly need to have those two lines of code there. 00:29:27.310 --> 00:29:28.378 But it's only two lines. 00:29:28.378 --> 00:29:29.170 So I think it's OK. 00:29:29.170 --> 00:29:32.128 And if you recall our discussion in the past, not just of correctness-- 00:29:32.128 --> 00:29:34.720 does the code work as it should?-- but design, 00:29:34.720 --> 00:29:36.400 I think you could argue it either way. 00:29:36.400 --> 00:29:38.860 If you prefer the readability of this and the fact 00:29:38.860 --> 00:29:41.050 that you don't have an else, that's fine. 00:29:41.050 --> 00:29:43.420 If, though, you prefer to minimize just how 00:29:43.420 --> 00:29:47.230 many lines of code you're trying to execute in case something goes wrong, 00:29:47.230 --> 00:29:50.050 the else is a reasonable approach too. 00:29:50.050 --> 00:29:53.050 Well, allow me to propose, too, now that we refine this further. 00:29:53.050 --> 00:29:56.290 I think we're at the point where it's pretty darn correct. 00:29:56.290 --> 00:30:00.250 But suppose now that I find myself today and tomorrow 00:30:00.250 --> 00:30:02.890 trying to get numbers from the user quite a bit. 00:30:02.890 --> 00:30:06.100 It would be nice, as we've seen, to maybe just invent my own function, 00:30:06.100 --> 00:30:10.160 get int to get an integer from the user both today and tomorrow and beyond. 00:30:10.160 --> 00:30:12.910 And, heck, maybe I can even share that function with other people. 00:30:12.910 --> 00:30:15.950 If they want to write programs, they get integers from users. 00:30:15.950 --> 00:30:17.767 So how might I go about doing this? 00:30:17.767 --> 00:30:19.850 Well, let me go ahead and propose that we do this. 00:30:19.850 --> 00:30:22.720 Let me get rid of the print line but keep most of my loop here. 00:30:22.720 --> 00:30:27.427 Let me define a function called get int that takes no arguments for now. 00:30:27.427 --> 00:30:30.010 And I'm going to go ahead and indent all of the code I already 00:30:30.010 --> 00:30:31.780 wrote underneath get int. 00:30:31.780 --> 00:30:37.390 So now I have a function called get int that tries to do the following. 00:30:37.390 --> 00:30:39.177 Try to get in it from the user. 00:30:39.177 --> 00:30:41.260 If something goes wrong and there's a value error, 00:30:41.260 --> 00:30:43.360 yell at them with x is not an integer. 00:30:43.360 --> 00:30:45.130 Else, break. 00:30:45.130 --> 00:30:47.890 But it's not just breaking that I want to do here. 00:30:47.890 --> 00:30:51.850 Now that I'm in a function, recall our discussion of return values. 00:30:51.850 --> 00:30:54.858 If you're inventing your own function whose purpose in life 00:30:54.858 --> 00:30:57.400 isn't just a print something on the screen like a side effect 00:30:57.400 --> 00:31:01.930 but is to hand back a value, to hand you back a value, 00:31:01.930 --> 00:31:05.180 like on that same post-it note from our discussion of functions, 00:31:05.180 --> 00:31:07.570 well, you need to return x explicitly. 00:31:07.570 --> 00:31:09.225 How do I now use this function? 00:31:09.225 --> 00:31:11.350 Well, as soon as we start making our own functions, 00:31:11.350 --> 00:31:14.590 it tends to be convenient to define our own main function as well. 00:31:14.590 --> 00:31:16.280 That's the main part of our program. 00:31:16.280 --> 00:31:17.697 And I'm going to keep this simple. 00:31:17.697 --> 00:31:20.380 I'm now going to say, x equals get int. 00:31:20.380 --> 00:31:23.500 And then on the next line, I'm going to do that print from before, quote 00:31:23.500 --> 00:31:25.870 unquote, "x is"-- in curly braces-- 00:31:25.870 --> 00:31:26.500 "x." 00:31:26.500 --> 00:31:28.960 And at the very bottom of my program recall, 00:31:28.960 --> 00:31:31.240 I'm going to call main, so that no matter what, 00:31:31.240 --> 00:31:34.480 I'm invoking my main function after everything's been defined. 00:31:34.480 --> 00:31:35.840 Well, let's see how this works. 00:31:35.840 --> 00:31:39.710 Let me go ahead and run Python of number.py. 00:31:39.710 --> 00:31:40.310 Enter. 00:31:40.310 --> 00:31:41.380 Let's type in 50. 00:31:41.380 --> 00:31:43.520 And it seems to work as before. 00:31:43.520 --> 00:31:47.330 Let's go ahead and run it again, typing in cat, C-A-T, this time. 00:31:47.330 --> 00:31:48.380 X is not an integer. 00:31:48.380 --> 00:31:49.520 And I'm being prompted. 00:31:49.520 --> 00:31:51.320 Dog, and I'm being prompted. 00:31:51.320 --> 00:31:52.850 Bird, and I'm being prompted. 00:31:52.850 --> 00:31:53.770 Fine, fine, fine. 00:31:53.770 --> 00:31:54.270 50. 00:31:54.270 --> 00:31:55.640 That's an int. 00:31:55.640 --> 00:31:57.200 And so it is printed. 00:31:57.200 --> 00:32:00.690 So what's worth noting here-- well, I'm manifesting a couple of good properties 00:32:00.690 --> 00:32:01.190 here. 00:32:01.190 --> 00:32:05.510 One, I've kind of abstracted away this notion of getting an integer. 00:32:05.510 --> 00:32:07.732 And even though I just artificially hit Enter 00:32:07.732 --> 00:32:10.190 a whole bunch of times just to hide that function for now-- 00:32:10.190 --> 00:32:13.190 it needs to be there, but we don't need to see it at this point-- notice 00:32:13.190 --> 00:32:15.350 that now this entire program really boils down 00:32:15.350 --> 00:32:17.480 to just these three lines of code now. 00:32:17.480 --> 00:32:18.110 Why? 00:32:18.110 --> 00:32:22.040 Because I've abstracted away that whole process of getting an int from the user 00:32:22.040 --> 00:32:25.250 into this new function of my own called get int. 00:32:25.250 --> 00:32:26.850 But can I improve upon this? 00:32:26.850 --> 00:32:29.660 Well, let me go and undo all of those blank lines 00:32:29.660 --> 00:32:32.330 and pull this up just so we can see more on the screen at once. 00:32:32.330 --> 00:32:34.910 Can I tighten up my implementation of get int? 00:32:34.910 --> 00:32:35.840 It is correct. 00:32:35.840 --> 00:32:37.220 I claim this is correct. 00:32:37.220 --> 00:32:38.330 It's handling errors. 00:32:38.330 --> 00:32:39.440 And it's returning x. 00:32:39.440 --> 00:32:43.170 But I don't, strictly speaking, need to write the code as long. 00:32:43.170 --> 00:32:44.790 What else could I do? 00:32:44.790 --> 00:32:48.710 Well, let me propose that if all you're doing on this line 13 is breaking 00:32:48.710 --> 00:32:51.530 and then immediately after that, per the indentation, 00:32:51.530 --> 00:32:56.450 you're executing return x on line 14, why are you wasting everyone's time? 00:32:56.450 --> 00:33:00.440 Once you know you're ready to return the value, you could just return x. 00:33:00.440 --> 00:33:03.900 And so in my else, I could break out and return a value. 00:33:03.900 --> 00:33:08.780 So here, too, return is used to return values from functions. 00:33:08.780 --> 00:33:11.780 Break is used to break out of loops. 00:33:11.780 --> 00:33:15.710 But it turns out that return is sort of stronger than break. 00:33:15.710 --> 00:33:17.960 It will not only break you out of a loop. 00:33:17.960 --> 00:33:20.510 It will also return a value for you. 00:33:20.510 --> 00:33:23.870 So it's doing two things for once, if you will. 00:33:23.870 --> 00:33:28.100 But can I make this even more compact? 00:33:28.100 --> 00:33:32.690 If my goal is to just tighten the code up, even though it's already correct, 00:33:32.690 --> 00:33:34.910 can anyone think of a further refinement, 00:33:34.910 --> 00:33:37.730 whether you've programmed in Python before or not? 00:33:37.730 --> 00:33:41.330 Can I shorten this implementation further just a little bit, 00:33:41.330 --> 00:33:43.610 if only to decrease the probability that I've 00:33:43.610 --> 00:33:45.980 made a mistake by having fewer lines and just 00:33:45.980 --> 00:33:49.100 make it a little easier to read because it's shorter? 00:33:49.100 --> 00:33:53.077 Any suggestions for tightening up my implementation of get int? 00:33:53.077 --> 00:33:55.160 AUDIENCE: You can just return the value on the try 00:33:55.160 --> 00:33:59.720 function, when you're trying. 00:33:59.720 --> 00:34:02.180 You take the input x and then return x. 00:34:02.180 --> 00:34:02.930 DAVID MALAN: Good. 00:34:02.930 --> 00:34:05.480 We can just return x a little higher up. 00:34:05.480 --> 00:34:07.030 And let me correct folks as we go. 00:34:07.030 --> 00:34:08.030 It's not a try function. 00:34:08.030 --> 00:34:09.739 It would be a try statement, technically. 00:34:09.739 --> 00:34:12.350 A function typically has a parentheses and another one. 00:34:12.350 --> 00:34:14.030 In this case, it's just a statement. 00:34:14.030 --> 00:34:15.690 But we can do exactly that. 00:34:15.690 --> 00:34:17.300 I don't technically need the else. 00:34:17.300 --> 00:34:19.340 If I really want, I could do this. 00:34:19.340 --> 00:34:22.520 Right after line nine, I could return x here. 00:34:22.520 --> 00:34:27.530 Or recall our discussion of defining variables unnecessarily sometimes. 00:34:27.530 --> 00:34:29.780 Why define a variable here if you're immediately going 00:34:29.780 --> 00:34:31.520 to use it here and then never again? 00:34:31.520 --> 00:34:33.860 So we could avoid a new line here. 00:34:33.860 --> 00:34:37.340 And I could avoid even defining x explicitly. 00:34:37.340 --> 00:34:39.080 I could just say something like this. 00:34:39.080 --> 00:34:42.889 I could return int, input, quote unquote, "what's x?" 00:34:42.889 --> 00:34:44.270 I can do it all at once. 00:34:44.270 --> 00:34:46.620 Now, which is better? 00:34:46.620 --> 00:34:47.580 I don't know. 00:34:47.580 --> 00:34:50.239 I mean, again, this is where reasonable people might disagree. 00:34:50.239 --> 00:34:53.210 I'd argue that, on the one hand, we're tightening up the code. 00:34:53.210 --> 00:34:54.650 We're using fewer lines. 00:34:54.650 --> 00:34:57.890 It's easier to read, lower probability that I've made a mistake. 00:34:57.890 --> 00:35:01.640 On the other hand, it's a little more complicated to understand, perhaps. 00:35:01.640 --> 00:35:04.070 It's a little less obvious where I'm returning from. 00:35:04.070 --> 00:35:06.050 So I think arguments can be made either way. 00:35:06.050 --> 00:35:09.530 At the end of the day, what's important is that you've done this consciously. 00:35:09.530 --> 00:35:12.180 You've made a decision to do it this way or this way. 00:35:12.180 --> 00:35:16.130 And you can justify it in your mind-- not that your answer is, eh, it worked, 00:35:16.130 --> 00:35:17.210 so I left it alone. 00:35:17.210 --> 00:35:18.080 Have a good reason. 00:35:18.080 --> 00:35:19.205 Come up with a good reason. 00:35:19.205 --> 00:35:22.010 And that will come with experience and practice. 00:35:22.010 --> 00:35:25.670 Well, let me propose to you that we make one other refinement here. 00:35:25.670 --> 00:35:28.910 Suppose that you're finding your programs to be a little noisy. 00:35:28.910 --> 00:35:31.370 And it's a little obnoxious that you keep telling the user, 00:35:31.370 --> 00:35:32.390 x is not an integer. 00:35:32.390 --> 00:35:33.410 X is not an integer. 00:35:33.410 --> 00:35:34.460 X is not an integer. 00:35:34.460 --> 00:35:38.780 What if you want to make things a little gentler and just prompt 00:35:38.780 --> 00:35:41.810 the user again with the same words, what's x? 00:35:41.810 --> 00:35:42.500 What is x? 00:35:42.500 --> 00:35:43.280 What's x? 00:35:43.280 --> 00:35:44.330 Again and again. 00:35:44.330 --> 00:35:45.930 Well, you can do that as well. 00:35:45.930 --> 00:35:49.970 And it turns out that if you want to handle an exception in Python 00:35:49.970 --> 00:35:54.590 but you want to pass on doing anything with it-- so you want to catch it, 00:35:54.590 --> 00:35:56.510 but you essentially want to ignore it. 00:35:56.510 --> 00:35:57.920 You don't want to print anything. 00:35:57.920 --> 00:35:59.720 You don't want to quit the program. 00:35:59.720 --> 00:36:02.330 You just want to silently ignore it, like 00:36:02.330 --> 00:36:05.460 if you're talking in a room full of people and it's your turn to talk 00:36:05.460 --> 00:36:07.070 and you're just like, pass. 00:36:07.070 --> 00:36:08.390 They're still calling on you. 00:36:08.390 --> 00:36:10.610 But you're not doing or saying anything more. 00:36:10.610 --> 00:36:13.250 Well, we can add this keyword to our code here. 00:36:13.250 --> 00:36:15.230 Let me go back to my program here. 00:36:15.230 --> 00:36:19.070 And instead of printing out again and again, x is not an integer, 00:36:19.070 --> 00:36:20.330 I could just do this. 00:36:20.330 --> 00:36:23.300 I could pass on handling the error further. 00:36:23.300 --> 00:36:24.500 I'm still catching it. 00:36:24.500 --> 00:36:28.040 So the user is not going to see a scary message even mentioning value error. 00:36:28.040 --> 00:36:29.390 My code is catching it. 00:36:29.390 --> 00:36:32.220 But I'm passing on saying anything about it. 00:36:32.220 --> 00:36:33.470 I'm going to stay in the loop. 00:36:33.470 --> 00:36:36.512 I'm going to stay in the loop and keep prompting and reprompting the user 00:36:36.512 --> 00:36:38.790 so now the effect looks a little something like this. 00:36:38.790 --> 00:36:40.470 Python of number.py. 00:36:40.470 --> 00:36:42.180 Let's type in cat. 00:36:42.180 --> 00:36:43.140 What's x again? 00:36:43.140 --> 00:36:44.310 Let's type in dog. 00:36:44.310 --> 00:36:45.430 What's x again? 00:36:45.430 --> 00:36:46.230 Type in bird. 00:36:46.230 --> 00:36:49.290 So it's just a little, maybe, more user friendly and that you're just 00:36:49.290 --> 00:36:50.820 reminding the user what you want. 00:36:50.820 --> 00:36:51.810 Maybe it's worse. 00:36:51.810 --> 00:36:54.630 Maybe it would be helpful to tell the user why 00:36:54.630 --> 00:36:56.500 you're prompting them again and again. 00:36:56.500 --> 00:36:57.250 It's not obvious. 00:36:57.250 --> 00:36:58.540 So it could go both ways. 00:36:58.540 --> 00:37:02.400 But, again, it's just another mechanism, now, for handling these errors. 00:37:02.400 --> 00:37:05.340 We use the except keyword to catch a specific error. 00:37:05.340 --> 00:37:07.620 But we don't have to handle it more than that. 00:37:07.620 --> 00:37:10.440 We can just pass on doing something further. 00:37:10.440 --> 00:37:15.480 Let me pause here and see if there's any questions now on try, accept, else, 00:37:15.480 --> 00:37:17.522 or pass? 00:37:17.522 --> 00:37:18.380 AUDIENCE: OK, yeah. 00:37:18.380 --> 00:37:18.880 No. 00:37:18.880 --> 00:37:22.220 I was just kind of curious, I guess, about the idea 00:37:22.220 --> 00:37:27.470 of when you were inventing with the get int function, for example. 00:37:27.470 --> 00:37:29.660 Because I'm noticing, obviously, going through it 00:37:29.660 --> 00:37:33.990 with the whole logic and breakdown of the entire function, while true, 00:37:33.990 --> 00:37:34.490 do this. 00:37:34.490 --> 00:37:37.198 But I'm just kind of curious in elaborating with the indentations 00:37:37.198 --> 00:37:38.660 for the code more. 00:37:38.660 --> 00:37:39.410 DAVID MALAN: Yeah. 00:37:39.410 --> 00:37:41.960 So the invitation is deliberate logically. 00:37:41.960 --> 00:37:45.500 Some languages don't require as rigorous indentation. 00:37:45.500 --> 00:37:47.780 You can use curly braces or other symbology 00:37:47.780 --> 00:37:49.940 to make clear what is associated with what. 00:37:49.940 --> 00:37:54.860 In general, any time you indent something in Python on this line-- 00:37:54.860 --> 00:37:58.250 rather, anytime you write a code a line of code in Python that's here 00:37:58.250 --> 00:38:00.950 and the lines below it are somehow indented, 00:38:00.950 --> 00:38:04.700 that means that those lines are somehow associated with that first line. 00:38:04.700 --> 00:38:07.370 And, presumably, those indented lines should only 00:38:07.370 --> 00:38:13.040 be executed if the first line told the computer to do so. 00:38:13.040 --> 00:38:14.900 So, concretely, what does this mean? 00:38:14.900 --> 00:38:17.660 On line six here, we're defining a function called 00:38:17.660 --> 00:38:20.660 get in that takes no arguments, colon. 00:38:20.660 --> 00:38:24.080 Everything that's indented by at least four spaces 00:38:24.080 --> 00:38:26.160 hereafter is part of that function. 00:38:26.160 --> 00:38:26.660 Why? 00:38:26.660 --> 00:38:29.450 That's just the design of the Python language. 00:38:29.450 --> 00:38:33.230 Frankly, I think the designers got tired of seeing really ugly code in languages 00:38:33.230 --> 00:38:40.310 like C and C++ and Java that don't necessarily enforce indentation to this 00:38:40.310 --> 00:38:40.980 extent. 00:38:40.980 --> 00:38:42.770 So now it's baked into the language. 00:38:42.770 --> 00:38:44.390 And my chronology might be a little off there. 00:38:44.390 --> 00:38:47.057 But there's been many languages that are looser than Python when 00:38:47.057 --> 00:38:48.980 it comes to indentation. 00:38:48.980 --> 00:38:51.770 The indentation is meaningful on line seven too. 00:38:51.770 --> 00:38:55.100 Notice that because the while true is indented by four spaces. 00:38:55.100 --> 00:38:57.270 That just means it's part of the get int function. 00:38:57.270 --> 00:39:01.400 But notice below the while true statement, there is eight, there's 12, 00:39:01.400 --> 00:39:03.435 there's eight, there's 12 spaces here. 00:39:03.435 --> 00:39:05.060 And I'm just quickly counting the dots. 00:39:05.060 --> 00:39:07.550 That means that all of the lines I've just highlighted 00:39:07.550 --> 00:39:09.590 are inside of that while loop. 00:39:09.590 --> 00:39:13.430 While true means to execute lines eight through 11, potentially, 00:39:13.430 --> 00:39:14.630 again and again and again. 00:39:14.630 --> 00:39:20.330 And now, lastly, on line eight, because we have try and indented below 00:39:20.330 --> 00:39:23.630 it is line nine, that just means that what you should try 00:39:23.630 --> 00:39:24.950 is what's on line nine. 00:39:24.950 --> 00:39:29.030 And similarly, on line 10, below it, we have indented line 11. 00:39:29.030 --> 00:39:33.840 You should only pass when there is an exception of a value error. 00:39:33.840 --> 00:39:37.043 So the indentation just means what is associated with what. 00:39:37.043 --> 00:39:38.960 And once you get comfortable with that, you'll 00:39:38.960 --> 00:39:43.670 see that the indentation alone helps explain the logic of your program. 00:39:43.670 --> 00:39:47.630 And it has a wonderful side effect that for yourself the next morning, 00:39:47.630 --> 00:39:51.080 for your colleagues, your family, your friends, your teachers, your code 00:39:51.080 --> 00:39:55.640 is much more readable as a result. It's not one big mess of a blob of text. 00:39:55.640 --> 00:39:59.780 Other questions now on try, except, else, or pass? 00:39:59.780 --> 00:40:01.460 AUDIENCE: Yeah, thanks. 00:40:01.460 --> 00:40:02.870 Two question. 00:40:02.870 --> 00:40:08.060 Question one-- once you say pass, can the caller 00:40:08.060 --> 00:40:14.420 still learn anything about this era through a system variable or whatever? 00:40:14.420 --> 00:40:19.410 And question two-- problem set zero referenced some string methods, 00:40:19.410 --> 00:40:21.680 including is numeric-- 00:40:21.680 --> 00:40:27.165 is it any different to [INAUDIBLE]? 00:40:27.165 --> 00:40:28.290 DAVID MALAN: Good question. 00:40:28.290 --> 00:40:30.860 So on the first question, if I'm handling the error in this way, 00:40:30.860 --> 00:40:32.943 the caller is not going to know anything about it. 00:40:32.943 --> 00:40:37.250 That's the point of my handling it, so that main or other callers don't know 00:40:37.250 --> 00:40:38.960 that anything technically went wrong. 00:40:38.960 --> 00:40:41.960 On the second question, is numeric is another function 00:40:41.960 --> 00:40:44.600 that you can call that can look at a string and determine 00:40:44.600 --> 00:40:46.340 is this, in fact, a number. 00:40:46.340 --> 00:40:48.650 I could use a mechanism like that. 00:40:48.650 --> 00:40:50.180 I could use a conditional. 00:40:50.180 --> 00:40:54.020 If this looks like a number, then pass it to the int function. 00:40:54.020 --> 00:40:56.030 And go ahead and convert it to an integer. 00:40:56.030 --> 00:40:57.410 That's totally fine. 00:40:57.410 --> 00:41:02.150 I would generally say that the Pythonic way of doing things is often, 00:41:02.150 --> 00:41:05.630 for better or for worse, to try things, hope they work. 00:41:05.630 --> 00:41:08.160 But if they don't, handle the exception. 00:41:08.160 --> 00:41:13.700 So other languages are more in favor of checking if, if, if, if, elif, else, 00:41:13.700 --> 00:41:15.080 and all of these conditionals. 00:41:15.080 --> 00:41:19.460 Python tends to be a little more of the mindset, eh, try it. 00:41:19.460 --> 00:41:21.510 But just make sure you're handling the error. 00:41:21.510 --> 00:41:23.438 So this would be the Pythonic way of doing it. 00:41:23.438 --> 00:41:26.480 Your way, though-- checking with the conditional, is it a number first?-- 00:41:26.480 --> 00:41:29.940 is totally reasonable too, if you want to go that way. 00:41:29.940 --> 00:41:32.000 Well, let me propose some final refinements 00:41:32.000 --> 00:41:34.970 to this program that really just kind of tighten things up, 00:41:34.970 --> 00:41:39.170 one additional step to improve the implementation of this 00:41:39.170 --> 00:41:40.220 get int function. 00:41:40.220 --> 00:41:44.870 Let me propose that we not hard code, so to speak-- that is type manually x 00:41:44.870 --> 00:41:45.900 all over the place. 00:41:45.900 --> 00:41:49.130 Let's make this function, get int, a little more reusable. 00:41:49.130 --> 00:41:53.870 Right now, notice that I'm just kind of using the honor system that, well, main 00:41:53.870 --> 00:41:55.940 is defining a variable called x. 00:41:55.940 --> 00:41:59.960 And get int is asking for a variable called x. 00:41:59.960 --> 00:42:02.720 But it would be nice if the caller, main, 00:42:02.720 --> 00:42:07.140 doesn't have to know what the call-ee is naming its variables and vise versa. 00:42:07.140 --> 00:42:09.620 So caller-- to call a function means to use it. 00:42:09.620 --> 00:42:11.750 The caller is the function that's using it. 00:42:11.750 --> 00:42:14.420 The call-ee is just the function being called. 00:42:14.420 --> 00:42:18.920 It would be nice if I'm not just hoping that x is the same in both places. 00:42:18.920 --> 00:42:20.530 So let me propose this. 00:42:20.530 --> 00:42:27.070 Let me propose that we actually add a parameter to get int, like this. 00:42:27.070 --> 00:42:28.330 What's x? 00:42:28.330 --> 00:42:31.540 That is to say, if main wants to use the get int function, 00:42:31.540 --> 00:42:35.110 well, then main should probably tell the get int function what 00:42:35.110 --> 00:42:36.310 prompt to show the user. 00:42:36.310 --> 00:42:40.090 Just like the input function, recall, that comes with Python, it's up to you 00:42:40.090 --> 00:42:45.320 to pass in a prompt that the user then sees when the human is asked for input. 00:42:45.320 --> 00:42:47.230 So how do I make this work here? 00:42:47.230 --> 00:42:49.390 I can go down to my definition of get int. 00:42:49.390 --> 00:42:53.080 And I can say, all right, get int is going to take a parameter now, 00:42:53.080 --> 00:42:53.770 called prompt. 00:42:53.770 --> 00:42:55.103 I could call it anything I want. 00:42:55.103 --> 00:42:57.550 But prompt in English is pretty self-explanatory. 00:42:57.550 --> 00:42:59.950 It means the message the user will see. 00:42:59.950 --> 00:43:02.800 And now, down here, when I actually use input, 00:43:02.800 --> 00:43:05.380 I don't have to presumptuously say, what's x? 00:43:05.380 --> 00:43:08.110 Because what if the program, the caller, wants 00:43:08.110 --> 00:43:10.900 to ask for y or z or some other variable? 00:43:10.900 --> 00:43:15.800 I can just pass to input whatever prompt the caller has provided. 00:43:15.800 --> 00:43:18.280 So now I'm making more reusable code. 00:43:18.280 --> 00:43:20.030 It still works just the same. 00:43:20.030 --> 00:43:22.120 I haven't changed the functionality, per se. 00:43:22.120 --> 00:43:24.490 But now it's a little more dynamic because now 00:43:24.490 --> 00:43:28.690 get int doesn't have to know or care what variable's being asked for, 00:43:28.690 --> 00:43:29.890 what's being asked for. 00:43:29.890 --> 00:43:33.410 It just needs to know what prompt it should show to the user. 00:43:33.410 --> 00:43:37.900 So if I now run this program down here, again, prompt number.py, Enter, 00:43:37.900 --> 00:43:38.620 what's x? 00:43:38.620 --> 00:43:40.480 50 still seems to work. 00:43:40.480 --> 00:43:41.300 Let's run it again. 00:43:41.300 --> 00:43:42.220 Let's type in cat. 00:43:42.220 --> 00:43:43.670 It still seems to work. 00:43:43.670 --> 00:43:46.210 And if I type in cat, dog, bird, or anything else, 00:43:46.210 --> 00:43:49.390 it will keep prompting me with that same prompt, making this code, 00:43:49.390 --> 00:43:51.730 therefore, all the more usable. 00:43:51.730 --> 00:43:55.150 Now it turns out, too, you can even raise exceptions yourself 00:43:55.150 --> 00:43:57.160 using Python's raise keyword. 00:43:57.160 --> 00:43:59.330 But more on that another time. 00:43:59.330 --> 00:44:01.960 So in the coming days, the coming weeks, the coming months, 00:44:01.960 --> 00:44:05.560 as you write more code in Python, you'll see that errors are inevitable. 00:44:05.560 --> 00:44:07.510 Sometimes they're syntax errors, which you've 00:44:07.510 --> 00:44:10.460 got to just fix if you even want to run your program at all. 00:44:10.460 --> 00:44:12.490 But they could be name errors-- for instance, 00:44:12.490 --> 00:44:15.880 variables that you meant to define but somehow didn't-- value errors, 00:44:15.880 --> 00:44:19.090 where maybe the user didn't cooperate and provided you with something that 00:44:19.090 --> 00:44:23.980 you weren't expecting, or a whole list of other possible errors or exceptions. 00:44:23.980 --> 00:44:26.800 But now, hopefully, you know how you can handle these errors 00:44:26.800 --> 00:44:29.080 and respond to them in any way you like. 00:44:29.080 --> 00:44:31.000 This, then, was our look at exceptions. 00:44:31.000 --> 00:44:33.720 And we'll see you next time.