Full transcript
Introduction
0:00[MUSIC PLAYING]
Exceptions
0:24DAVID MALAN: All right, this is CS50's introduction
0:27to programming with Python.
0:28My name is David Malan.
0:29And this is our week on exceptions.
0:31Exceptions in Python as well as in other programming languages
0:35refer to problems in your code.
0:37Indeed, when something is exceptional in your program,
0:40it actually doesn't mean it's a good thing.
0:41It means something has gone wrong that, ideally, you will somehow solve.
0:45So what are some of the things that can go wrong?
0:47So I'm going to go ahead and open up VS Code on my computer here.
0:50And in the terminal window, I'm going to go ahead and run code of hello.py.
SyntaxError
0:54That's going to, of course, open up a brand
0:56new tab for me, hello.py, in which I can write my code.
0:59And let me go ahead and write some very simple code just
1:01to say hello to the world.
1:03Let's go ahead and say print "hello, world.
1:08And then let me go ahead and--
1:10I'm forgetting to close that quote.
1:12So a mistake that you yourself might have already made
1:14or might surely in the future make-- and it's a little subtle
1:17because you might not necessarily notice that you've just
1:19missed that one character.
1:20Well, let me go ahead and somewhat optimistically
1:23go down to my terminal window now and run Python of hello.py and hit Enter.
1:28And that's the first of my errors.
1:29My gosh, I've only written one line of code.
1:31And I seem to have more lines of errors on the screen.
1:34But the salient point is this bottom-most thing here.
1:37Notice where it says syntax error.
1:39A syntax error is a problem with the code that you have typed, your syntax.
1:43Just like English and other human languages
1:45have syntax associated with them, so does my code.
1:47And it's not quite correct.
1:49Something is awry.
1:50I didn't follow the instructions properly.
1:52And it does elaborate for me, unterminated string literal.
1:56Now, that's a bit arcane.
1:57That is a bit of a confusing error message.
1:59But unterminated would generally mean that I
2:01started something but didn't stop it.
2:03I didn't terminate it.
2:05String, of course, is a sequence of text, like we've discussed before--
2:08or stir in Python.
2:09And literal generally refers to something that you literally typed.
2:13It's not a variable.
2:14It's something like quote unquote--
2:15or just "hello world.
2:18So the fix here, of course, is going to be
2:20to go ahead and terminate that string and actually close the quote.
2:24And if I now go back down into my terminal window
2:27and rerun Python of hello.py, now I'm saying hello to the world.
2:31So the catch with syntax errors here is that syntax errors are entirely
2:36on you to solve.
2:37A syntax error is a problem that you've got to go back into your code
2:40and fix from the get-go.
2:41You can't just kind of hope that it's going
2:43to resolve itself or expect that other parts of your code
2:47will catch it for you.
2:48Syntax errors just must be fixed.
2:50But there's a lot of other types of errors in Python
2:53that might be described as runtime errors, that
2:55happen while your code is running.
2:57And it's really up to you to write some additional code defensively
3:01to detect when those errors happen because you don't necessarily know,
3:05for instance, what input humans are going to type into your program.
3:08And so you better be ready, defensively, to accommodate things
3:11that they type or even misstype.
3:13So, for instance, let's go back over here to VS Code.
3:17And let me propose that we take a look at a new file all together.
3:20I'm going to close hello.py.
3:22And I'm going to write code of say number.py.
3:26So let's play around with some numbers in Python.
3:28And the first thing I'm going to go ahead here and do with number.py,
ValueError
3:32after opening this new tab, is I think I'm going to go ahead and print--
3:35type up a relatively simple program that maybe prompts the user for an integer,
3:40like x, and then just prints out what x is.
3:43So we're going to start simple, but, again, in starting simple,
3:45we'll be able to really see where I've done something wrong.
3:48Well, here we go.
3:49I'm going to go ahead and say a variable called
3:51x is going to get assigned the value of the return value of input,
3:57quote unquote, "what's x?"
3:59And I'm going to include a space to move the cursor over a little bit.
4:02And then, ultimately, I'm going to go ahead and-- oh, wait a minute.
4:05If I'm wanting to get an int from the user,
4:08recall that I need to do something proactively.
4:10I need to actually convert that input to an integer using
4:14the int function in Python.
4:16So now I'm passing the return value of input as the argument to int.
4:20And that will store in x, ultimately, an integer, not
4:22a string that looks like an integer.
4:24All right, let me go ahead now and just quite simply print out what this is.
4:28I'm going to go ahead and print out, quote unquote, "x is x."
4:32But I don't want to literally say x is x.
4:34I want to plug in the value of x.
4:36So maybe the easiest way to do that is to surround it with curly braces.
4:40And then if I'm using these curly braces and I
4:42want Python to interpolate the value of that variable,
4:45that is substitute what x actually is in between those curly braces,
4:49recall that I need to use a format string or an F-string
4:52by fixing this whole thing with an F. Now that I've done that, let's go ahead
4:56and see what happens.
4:57I'm going to go ahead in my terminal window and run Python of number.py.
5:02I hit Enter.
5:02And so far, so good.
5:03All is well and being prompted for x.
5:05Let me go ahead and type in a number like 50.
5:08All right, that seems to work.
5:09Program seems to be correct.
5:12Or is it?
5:14What could go wrong in this program, even though nothing did just go wrong?
5:19But if I run it and run it and run it again,
5:22during the running of my program, what could still go wrong,
5:26especially if I'm not the human interacting with it
5:28but some other human instead?
5:30Any volunteers here for this one?
5:33What could go wrong?
5:35And in what way is this program not really correct, even
5:40though at first glance it seems so.
5:42AUDIENCE: [INAUDIBLE]
5:52DAVID MALAN: So I'm not calling an integer.
5:54I'm still having trouble hearing you.
5:56But what I think I heard is that if what the user types in is not,
5:59in fact, an integer, I can't just blindly convert it to an int.
6:03If I'm not putting too many words into your mouth,
6:05I think what I should perhaps do here is be a little defensive.
6:10And let me see if I can't simulate exactly the problem that
6:14could go wrong here.
6:14Let me go ahead and run, again, Python of number.py.
6:18Let me try another number.
6:19In fact, when testing your code, generally it's
6:21a good idea to test corner cases, maybe numbers that aren't quite as plain as
6:25or 49 or 51.
6:27Let's choose some numbers that might be a little more interesting, if only
6:30mathematically, like zero.
6:32All right, zero seems to work.
6:34My code still prints out that x is zero.
6:35What might be another corner case to consider?
6:37Well, let me go ahead and try a negative number.
6:39That, too, is pretty different in spirit from negative.
6:42Negative 1?
6:43OK, that works too.
6:44Well, let me try it one more time.
6:46I've tried positive numbers, negative numbers, 0.
6:48Let me try something like a cat.
6:50So literally, C-A-T-- typing in a string that doesn't even look like a number.
6:56And yet, let's see now what happens when I hit Enter.
6:58All right, we'll see now we've got another kind of error.
7:01It's not a syntax error, because I didn't make a typographical mistake.
7:05I didn't forget some piece of syntax.
7:07I actually now have an error with one of my values.
7:10And it's an a value I didn't even anticipate.
7:12The human, me, in this case typed it in long after I wrote the code.
7:17So what does this refer to?
7:18A value error.
7:19Well, let's see what the explanation is.
7:21Invalid literal for int with base 10, quote unquote, "cat."
7:25Now, this, too, is a bit of a mouthful.
7:27And, unfortunately, in Python and a lot of programming languages,
7:29the error messages are written for pretty comfortable programmers.
7:32And, of course, when you're learning programming for the first time,
7:35you might not be so comfortable with the programming language
7:38let alone the error messages.
7:40But let's see if we can't glean some insight.
7:42So invalid literal.
7:43Well, again, a literal is just something that's been typed in, it would seem,
7:47for int.
7:48What is int exactly?
7:50Well, int is the function I'm using to convert the user's
7:52input to a corresponding integer.
7:55Base 10, that refers to the decimal system, which is this
7:58the default that Python is using.
7:59And it looks like at the end of the day, what Python really
8:02doesn't like is that I passed cat, quote unquote, "to the int function."
8:07So how do I go about actually fixing this problem?
8:10Well, I could just add instructions in my program.
8:13Maybe I could add a line of print telling
8:15the user more explicitly, be sure to type an integer,
8:18or, please don't type cat.
8:20Please don't type strings.
8:21Of course, the user might still not oblige.
8:23They might not be reading the instruction.
8:25So that too is probably not an effective strategy.
8:27What we really want to do is write our code with error handling in mind.
8:31We want to write lines of code that not only accomplish
8:33the problems we care about but that also handle
8:36errors that might unexpectedly happen.
8:39And, in general, when programming, programming defensively.
8:41Assume that the users aren't going to be paying attention or, worse,
8:44they're malicious.
8:45They're trying to crash your program.
8:47So we want to handle as many errors as we can.
8:50Now, how do we go about doing that in Python?
try, except
8:52Well, it turns out whether you want to catch a value error or other types
8:56of errors as well-- though not syntax error--
8:59Python actually has this keyword called try.
9:01And it's sort of aptly named.
9:02If you want to try to do something in Python,
9:05you can literally use this keyword.
9:07And you can check whether or not something exceptional, something
9:11erroneous, has happened.
9:12So using both try and this other keyword, except,
9:16can I go and try to do something except if something goes wrong?
9:20I can do something else instead.
9:22So let's consider, how can I go about trying
9:25to convert the user's input to an int except if something goes wrong?
9:29Well, let me go back to my code here.
9:31And let me propose that I now modify this example as follows.
9:34Let me go ahead and, above my first line of code,
9:37I literally write, try and a colon, telling Python,
9:40try to do the following.
9:42I'm going to go ahead and indent my existing lines of codes
9:44here by the same number of spaces, four in this case.
9:47And then I'm going to add one more new line down here that literally says,
9:51except Value Error.
9:53And notice it's important that I've capitalized the V
9:55and I've capitalized the E. These symbols are case sensitive.
9:59And this is now an opportunity, after this colon,
10:02to tell Python what I want to do in exceptional cases, when
10:07the number or the input from the user is not, in fact, a number.
10:10And I'm going to say something plain like print, quote unquote,
10:13"x is not an integer."
10:15I'm at least going to tell the user roughly what the problem actually is.
10:19So notice another detail.
10:21The indentation is important.
10:22Because I have try on line one and I've indented lines two and three, those
10:26are the two lines of code that I'm trying, except if I see a value error,
10:30line five, because it's indented is what is
10:33going to get executed in cases of those errors.
10:36Let me go ahead now back to my terminal window and run Python of number.py,
10:43Enter.
10:44And let's go ahead and type in again.
10:47Still seems to work.
10:48And, of course, I'm trying and succeeding.
10:50Let me go ahead and try once more, this time, though, with the word cat
10:53or, really, anything that's not a decimal number.
10:55And now you'll see much more cleanly x is not an integer.
10:59I'm not seeing some scary error message that I, the user,
11:02am going to have no idea how to handle.
11:04Now you, the programmer, have anticipated
11:06that something exceptional can happen.
11:08And you've gone about actually handling the error for the user,
11:12giving them an appropriate error message instead.
11:15Let me pause here and see, are there any questions now
11:18on what we've just done by introducing try
11:21and accept to handle this value error?
11:25AUDIENCE: Is value ever the only type of error you can get?
11:28Or are there other types?
11:29DAVID MALAN: Is value error the only thing you can catch?
11:31There are other errors as well.
11:32And we'll see a few of them today.
11:33And there's many, many more, honestly, that if you continue
11:36programming and programming in Python, you're
11:38going to see a lot of them over the weeks the months the years to come.
11:41But the technique for handling them is going
11:43to be largely the same other questions on try, accept,
11:47or these exceptions more generally?
11:49AUDIENCE: Yes, sir.
11:51Actually, to use the except block, you need to know the type of error, right?
11:55[INAUDIBLE] what if you can't anticipate this particular type of error?
12:01DAVID MALAN: A really good question.
12:02So I'm being very good about catching, so to speak,
12:06the very error that I might happen.
12:08I don't know when it might happen because it's
12:10going to depend on the user.
12:11But I know what kind of error will happen from the int function.
12:15There is a way in Python where you can say, except if anything goes wrong.
12:19And you can literally omit value error and just catch everything.
12:23The problem with that is that it sometimes hides other bugs in your code
12:27because you don't necessarily know what's going wrong.
12:29And if you don't necessarily know what's going wrong,
12:32how can you possibly handle it correctly?
12:34So bad practice.
12:35And it put another way, it's lazy to do that, to just say, catch everything
12:38and I'll deal with it here.
12:40So a much better practice would be to figure out what kind of errors
12:43could happen and include mention of them explicitly, as I have done.
12:48Now, with that said, if you read Python's official documentation,
12:51as you'll eventually invariably do, it is not
12:54great about telling you proactively what kinds of errors
12:58can be raised in this way.
13:00So it's a bit of contradictory advice.
13:03You should do it this way.
13:04But it's not always obvious what you should be checking for.
13:07But you get better at it with practice.
13:09And some of the times, the documentation does spell out what could go wrong.
13:12Let me turn our attention now back to this
13:14and point out that even though this is better code,
13:17it is more correct in the sense that I'm not just leaving it to the user
13:21to see some really ugly default Python error message that most people are
13:25going to have no idea what to do with, I'm
13:27at least handling it more elegantly.
13:29And I'm printing out x is not an integer.
13:31So it's at least more instructive.
13:33But this isn't necessarily the best way to implement this code.
13:36Why?
13:36Well, here, too, I'm actually still being a little lazy.
13:39So notice that I'm trying to do not one line of code but two lines of code.
13:44And this isn't a huge deal because we're only talking about two lines of code.
13:47But in the interest of preaching best practices,
13:51you should really only be trying to do the one or very few lines of code that
13:56can actually raise an exception that can actually fail in some way.
14:01I am pretty sure that calling print here is not going to raise a value error.
14:06Whether x is an int or a string or a float or anything else,
14:10the format string feature of Python is going to handle printing it just fine.
14:15So, really, what I'm going to do is this.
14:17I'm going to move this line three down to the bottom of my code.
NameError
14:21I no longer need to indent it.
14:22I'm just going to execute it at the bottom of my file here.
14:26Unfortunately, by doing this--
14:28I've done a good thing by now only trying to do the minimal amount of work
14:32necessary that might raise the exception of value error.
14:36But I fear I've introduced a new mistake.
14:38Well, let's see.
14:39What is now incorrect?
14:40Let me go ahead and again run Python of number.py, Enter.
14:44Let me go ahead and do it correctly with 50.
14:46And all seems to be well.
14:48But, again, let's try those corner cases--
14:50the zeros, the negative numbers, or, in this case, the cat.
14:52Let me go ahead and type in C-A-T again.
14:55Enter.
14:55Now I have a name error.
14:57So now it's yet another type of error in my code that I've introduced here.
15:01And what does this name error mean?
15:03Well, just as a value error refers to that-- the value of some variable,
15:07the value that someone has typed in is incorrect--
15:09name error tends to refer to your code, like you're doing something with
15:13the name of a variable that you shouldn't.
15:16And why might that be?
15:17Well, let me turn our attention back to the code
15:19here and consider, what is it complaining about?
15:22Well, the name errors what I see down here.
15:24And it's telling me, name, quote unquote, "x is not defined."
15:28And notice if I look further here, it is mentioning line six.
15:31So I know the problem is with my code on line six.
15:35And that worked a moment ago.
15:38And I'm defining x on line two.
15:42But let me ask the group here, why does x, in fact, exist online six?
15:48Why is it not defined, even though I'm pretty sure I
15:52was intending to define it on line two?
15:54AUDIENCE: Maybe the scope of the variable is between the [INAUDIBLE]..
16:00DAVID MALAN: So, good terminology.
16:02Scope refers to the portion of code in which a variable exists.
16:06That, too, though isn't quite right in Python.
16:08That would be true in C, C++, and Java, where indentation or curly braces tend
16:12to define the scope of a variable.
16:15But, again, here in general--
16:16and this worked a moment ago.
16:18X exists once it's defined on line two because, remember,
16:22I printed out x is 50 a little bit ago.
16:24Let's try one more hypothesis here.
16:27One more hand?
16:29Why is x somehow still not defined?
16:32AUDIENCE: Yeah, so is it because it's local variable,
16:36meaning that it doesn't define outside of the scope
16:39because what people have mentioned.
16:42It prompts the input in try, right?
16:45The outside of it is undefined.
16:46DAVID MALAN: So still good instincts.
16:48And good terminology, too.
16:49There's this notion of local variables, which tend to exist inside
16:52of functions, for instance, global variables,
16:55which tend to exist in entire files.
16:57In this case, too, though, that's not quite the case.
16:59What's happening here boils down to order of operations.
17:03Let me come back to the code here and recall that any time we've
17:06discussed the assignment operator, the single equal sign, that copies
17:09a value from the right to the left.
17:11But consider for a moment at what point something is going wrong.
17:14Well, the input function is probably working just fine
17:17because we've used that a lot now to get users' input.
17:20It always returns a string or a stir in Python.
17:24But what could be going wrong?
17:25Well, if I'm passing that string to the int function as its argument,
17:32it's probably the int's function that's erroring.
17:34And, indeed, if you think back earlier when we had the value error,
17:37it was, in fact, the int function that did not
17:39like, quote unquote, "cat" as input.
17:42So this is all to say that this portion of my code
17:45highlighted now to the right of the equal sign, that's
17:48the code that's creating a problem.
17:50That's the code that was creating a value error.
17:53And in this case, we're catching the value error.
17:57But because the value error is happening on the right of the equal sign,
18:01there's no value being copied to the left.
18:03The error is interrupting that whole process.
18:06So even though we see x equals dot dot dot on line two,
18:10the portion of that line to the left of the equal sign
18:13isn't getting evaluated, ultimately, because the value
18:16error is happening too soon.
18:18And so when we finally get down to line six,
18:20even though it looked like I was defining on line two--
18:23and I would have defined x on line two if all had gone well--
18:26we didn't get to the part where the value is copied from right to left
18:29because the value error happened first.
18:31So this code is just incorrect now.
18:34So how do I go about solving something like this?
else
18:37Well, it turns out that there's another feature of the try
18:41and accept syntax that Python supports, which is
18:43that it also supports the keyword else.
18:46Now, we've seen else before.
18:47If you think back to our discussion of conditionals, we saw if.
18:51We saw elif.
18:52We saw else, which was kind of this catchall, what
18:55you should do in the event that nothing else is relevant.
18:58That's kind of the same intuition here for the try-except feature of Python.
19:02What you can do is this.
19:04You can try to do the following, as I've done, except if this goes wrong.
19:09But if nothing goes wrong, else go ahead and do this.
19:13So this is one way I can solve this same problem now.
19:16No matter what now, Python is going to try to execute line two.
19:21If something goes wrong, it's going to execute lines three
19:24and four to handle that value error.
19:26However, if you try and this code succeeds,
19:30then there is no exception to handle.
19:32So you're then going to execute this line here.
19:35So it's a little confusing, perhaps, in that
19:37we're now using else both for conditionals-- if, elif, elif, elif,
19:41else.
19:42And we're also using else with these try-except blocks.
19:45But that's OK.
19:46That's part of the language.
19:47That's one of the features.
19:48So now if I rerun this code in my terminal window, Python of number.py--
19:54let's do something correct, like 50--
19:56I see that x is 50.
19:58So line one is executed.
20:00We're trying to do the following.
20:01Line two is executed because the conversion happened successfully
20:05and the number 50 gets copied from right to left.
20:07The exception does not happen.
20:10So we ignore lines three and four.
20:11We jump immediately to line five and six, which prints out the result.
20:16By contrast, though-- let's do this one last time.
20:18Python of number.py-- let's type in cat or, again, any other word and hit Enter
20:23now.
20:23We don't see what x is.
20:25Rather, we see, quote unquote, "x is not an integer,"
20:29which is what's being handled in my except clause.
20:33All right, let me pause here because that's a lot of new syntax,
20:35and see here if there's any questions on try, on except,
20:39on else, name error, or value error.
20:42AUDIENCE: Can you please repeat the try function?
20:45DAVID MALAN: Repeat the name error?
20:47What's the problem with the name error?
20:48AUDIENCE: Yes.
20:49Yes.
20:49DAVID MALAN: Yes.
20:50So let's just rewind a couple of lines here
20:52before I fix this problem by now getting rid of the else.
20:55A moment ago, we had code that looked like this, whereby
21:00I was getting a name error, Python of number.py, Enter,
21:03typing in cat, that looked like this, where name x is not defined.
21:07And the problem was on line six, according to this output in Python.
21:11Well, let's think about this now deductively.
21:13Let's try a different approach.
21:15On line six, I'm seeing an error that name x is not defined.
21:18OK, Python's already telling me x does not exist at that point.
21:22So how could that possibly be?
21:23Well, where should x be defined?
21:26Well, presumably, x is defined on line two, up here.
21:29So what could go wrong?
21:31Well, if the user has inputted something that doesn't look like a number,
21:35like the word cat, passing cat, the return value of input,
21:40as the argument to int to convert the word to an int makes no sense.
21:45You can't convert a cat, C-A-T, to an integer at all.
21:49So the int function is raising a value error at that point.
21:55And the error is being handled with this code here.
21:58But notice this line six is not indented.
22:02It's left aligned with the rest of my code, which means no matter what,
22:06line six is going to execute.
22:08It's going to execute whether I typed in 50 or I typed in cat.
22:12But if I typed in cat, again, x never gets a value.
22:15So it's not defined here on line six.
22:17So when I introduced, finally, the else statement, that
22:21makes sure that these things are mutually exclusive.
22:23I only execute the else if I tried and succeeded up above.
22:29Well, let me propose that we refine this just a little bit further as well
22:35and consider how we might improve this example a little bit more.
22:39It's a little unfriendly of me to be rejecting the user's input after they
Reprompting, break
22:45fail to provide an integer and just quitting the program, really, right?
22:49It'd be more user friendly if I just prompt
22:51or reprompt the user again and again.
22:54And in the chat, if you could, what's the feature of Python
22:58that you can use if you want to do something again and again
23:01and again until such time as the user cooperates and gives you
23:04what you're looking for, like a number?
23:07So yeah, loop, loop, loop.
23:09So a loop is something that happens again and again and again.
23:12And maybe we can use that same mechanism, a loop, in order
23:15to prompt the user for x.
23:17And if they don't give us a number, prompt them again.
23:19And if they don't, prompt them again and again and again.
23:22We don't need to just quit out of the program.
23:24So, quickly-- so let me propose this.
23:26Let me propose here that I improve this code by deliberately doing this.
23:30Let me induce a infinite loop at the very top of my code with while true.
23:36Recall that the wild keyword induces a loop, a cycle that behaves like this.
23:40And it asks a question, a Boolean expression
23:42that needs to evaluate either to true or false.
23:45Well, if I want this thing to loop forever,
23:47at least initially, we'll just say while true because true is true.
23:51So this has the effect of doing something
23:53no matter what forever unless we break out of it early.
23:56Now I'm going to go ahead and do this.
23:58I'm going to go ahead and move my try except code
24:02indented underneath this loop so that I'm trying to get an x.
24:06If I have a value error instead, I print out x is not an integer.
24:11But this time, what do I want to do if the user does
24:15try and succeed in giving me a number?
24:18Well, I can do this.
24:20I can just break out of my code here.
24:22And down here now, I can use that same line of code
24:25from before, an F-string that says x is, and then in curly braces, x again.
24:31So what's going on here?
24:32I think this code now, because I've added
24:35the loop, is going to have the effect of trying at least once, maybe
24:39a second time, maybe a third time maybe 500 times until the user finally gives
24:44me what I want, which is an integer.
24:46And once they do, once there's no value error happening,
24:50then I break out of the loop.
24:51And line nine executes as I would hope.
24:54So let me go ahead and try executing this version--
24:56Python of number.py, Enter.
24:58What's x?
24:59Let me go ahead and type in the easy thing first--
25:0250.
25:03X is 50.
25:03What just happened in terms of the control flow
25:06of this program, the flow of my logic?
25:08Well, I first found myself on line one inside of a loop.
25:11Hopefully, I'll get out of this loop.
25:13What did I then do?
25:14On lines two and three, I tried to get input from the user
25:18and convert it to an int.
25:19Well, I was a nice guy this time.
25:20And I typed in 50, which looks like and is a number.
25:23So the int function converted it just fine
25:25and stored it from right to left in x.
25:28Except value error?
25:29There is no value error because if I typed in a number,
25:31there's nothing exceptional happening.
25:33This is a boring, good execution of my program.
25:36So what happens?
25:38I break out of the loop.
25:39So, again, the else clause is associated with the try not with the except.
25:44And once I'm out of the loop, of course, I'm just printing out what x is.
25:47Well, let's try the other scenario that might happen.
25:50Python of number.py, Enter.
25:52What's x?
25:53Let's try cat or any other word.
25:55Enter.
25:56Ah, this is now a new feature.
25:59I'm being informed what I did wrong.
26:01X is not an integer.
26:02So I'm getting some useful user feedback.
26:05But notice, again, I'm prompted, what's x?
26:07Well, let me try typing in dog.
26:09X is not an integer.
26:11What's x?
26:11Let me try bird.
26:13Enter.
26:14X is not an integer.
26:15What's x?
26:15And suffice it to say, this will happen now forever if I'm in an infinite loop
26:19until I try and succeed, at which point I break out.
26:23So let's try again.
26:2450, Enter.
26:25Now I'm out of the loop.
26:26And I'm printing out what x actually is.
26:30All right, let me pause here and see if there are any questions.
26:33The logic is almost the same.
26:35But what is different now is I'm in a loop.
26:38And I'm using the keyword break in Python
26:40to deliberately break out of the loop when I'm
26:43ready to, once the user has cooperated.
26:46AUDIENCE: Do we really need to break?
26:48Can't we just print?
26:51Or what keeps us from just printing?
26:54DAVID MALAN: Good question.
26:55So let me try that.
26:56Couldn't I just print?
26:57Well, let's see what happens if I do that.
26:59Let me move this print line at the end into my loop
27:02here, thereby shortening the program.
27:04And, in general, that's been a good thing.
27:06Python of number.py, Enter.
27:08Let me go ahead and type in 50.
27:10OK, x is 50.
27:11What's x?
27:13OK, maybe it's 49.
27:14X is 49.
27:15OK, maybe 48.
27:17Unfortunately, I think-- you're laughing.
27:19You see it.
27:19I never break out of the loop, which maybe that's a feature.
27:22Maybe you want this to be your program.
27:23But I didn't.
27:24I'd eventually like this game to stop.
27:25So I need to break out in that way.
27:28But I can do it a little differently.
27:29And let me propose that we modify this a little bit.
27:33But, first, any other questions on this syntax here?
27:36Let me rewind to the prior version.
27:41AUDIENCE: Hi, can I use a break [INAUDIBLE] except and else?
27:46For example, in another print, may you use printing the else,
27:51you can use prints together with break or something like this?
27:55DAVID MALAN: So you can use break inside of loops to break out of loops.
27:59And you can use it inside of a conditional,
28:01like an if, an elif, or an else.
28:03You can do it inside of a try, except, else statement to.
28:06Any time you're in a loop that you want to break out
28:09of, you can use this keyword, break.
28:11I'm using it in the context of exceptions.
28:13But it's not restricted to that.
28:14And let me show you, too.
28:15It doesn't even have to be in the else.
28:17If I wanted to, I could actually do this.
28:20I could get rid of my else.
28:21And I could go back to line three, add another line that's indented,
28:26line four, and break out here.
28:28Now, why is this logically OK?
28:31Well, consider what I'm now trying to do.
28:34I'm trying to execute line three and converting the user's input to an int.
28:38And I'm trying to store the result from right to left in x.
28:42If something goes wrong, the code we've already seen
28:45is immediately going to jump to line five
28:48and then six to handle the exception.
28:51But if nothing goes wrong, my code presumably
28:54should just keep on executing line by line.
28:57So I could technically logically put the break here.
29:00And watch what happens when I run this version.
29:02Python of number.py, 50, Enter, it worked.
29:06I broke out of the loop.
29:08Now, which way is better?
29:09Honestly, I think it could go either way at this point.
29:12This program is so relatively short that even
29:15though I'm trying to do two things now, one of which, the break,
29:18is not going to fail.
29:19You either break or you don't.
29:21There's no piece of data from the user that's going to influence that.
29:24We don't strictly need to have those two lines of code there.
29:27But it's only two lines.
29:28So I think it's OK.
29:29And if you recall our discussion in the past, not just of correctness--
29:32does the code work as it should?-- but design,
29:34I think you could argue it either way.
29:36If you prefer the readability of this and the fact
29:38that you don't have an else, that's fine.
29:41If, though, you prefer to minimize just how
29:43many lines of code you're trying to execute in case something goes wrong,
29:47the else is a reasonable approach too.
get_int
29:50Well, allow me to propose, too, now that we refine this further.
29:53I think we're at the point where it's pretty darn correct.
29:56But suppose now that I find myself today and tomorrow
30:00trying to get numbers from the user quite a bit.
30:02It would be nice, as we've seen, to maybe just invent my own function,
30:06get int to get an integer from the user both today and tomorrow and beyond.
30:10And, heck, maybe I can even share that function with other people.
30:12If they want to write programs, they get integers from users.
30:15So how might I go about doing this?
30:17Well, let me go ahead and propose that we do this.
30:19Let me get rid of the print line but keep most of my loop here.
30:22Let me define a function called get int that takes no arguments for now.
30:27And I'm going to go ahead and indent all of the code I already
30:30wrote underneath get int.
30:31So now I have a function called get int that tries to do the following.
30:37Try to get in it from the user.
30:39If something goes wrong and there's a value error,
30:41yell at them with x is not an integer.
30:43Else, break.
30:45But it's not just breaking that I want to do here.
30:47Now that I'm in a function, recall our discussion of return values.
30:51If you're inventing your own function whose purpose in life
30:54isn't just a print something on the screen like a side effect
30:57but is to hand back a value, to hand you back a value,
31:01like on that same post-it note from our discussion of functions,
31:05well, you need to return x explicitly.
31:07How do I now use this function?
31:09Well, as soon as we start making our own functions,
31:11it tends to be convenient to define our own main function as well.
31:14That's the main part of our program.
31:16And I'm going to keep this simple.
31:17I'm now going to say, x equals get int.
31:20And then on the next line, I'm going to do that print from before, quote
31:23unquote, "x is"-- in curly braces--
31:25"x."
31:26And at the very bottom of my program recall,
31:28I'm going to call main, so that no matter what,
31:31I'm invoking my main function after everything's been defined.
31:34Well, let's see how this works.
31:35Let me go ahead and run Python of number.py.
31:39Enter.
31:40Let's type in 50.
31:41And it seems to work as before.
31:43Let's go ahead and run it again, typing in cat, C-A-T, this time.
31:47X is not an integer.
31:48And I'm being prompted.
31:49Dog, and I'm being prompted.
31:51Bird, and I'm being prompted.
31:52Fine, fine, fine.
31:5350.
31:54That's an int.
31:55And so it is printed.
31:57So what's worth noting here-- well, I'm manifesting a couple of good properties
32:00here.
32:01One, I've kind of abstracted away this notion of getting an integer.
32:05And even though I just artificially hit Enter
32:07a whole bunch of times just to hide that function for now--
32:10it needs to be there, but we don't need to see it at this point-- notice
32:13that now this entire program really boils down
32:15to just these three lines of code now.
32:17Why?
32:18Because I've abstracted away that whole process of getting an int from the user
32:22into this new function of my own called get int.
32:25But can I improve upon this?
32:26Well, let me go and undo all of those blank lines
32:29and pull this up just so we can see more on the screen at once.
32:32Can I tighten up my implementation of get int?
32:34It is correct.
32:35I claim this is correct.
32:37It's handling errors.
32:38And it's returning x.
32:39But I don't, strictly speaking, need to write the code as long.
32:43What else could I do?
32:44Well, let me propose that if all you're doing on this line 13 is breaking
32:48and then immediately after that, per the indentation,
32:51you're executing return x on line 14, why are you wasting everyone's time?
32:56Once you know you're ready to return the value, you could just return x.
33:00And so in my else, I could break out and return a value.
33:03So here, too, return is used to return values from functions.
33:08Break is used to break out of loops.
33:11But it turns out that return is sort of stronger than break.
33:15It will not only break you out of a loop.
33:17It will also return a value for you.
33:20So it's doing two things for once, if you will.
33:23But can I make this even more compact?
33:28If my goal is to just tighten the code up, even though it's already correct,
33:32can anyone think of a further refinement,
33:34whether you've programmed in Python before or not?
33:37Can I shorten this implementation further just a little bit,
33:41if only to decrease the probability that I've
33:43made a mistake by having fewer lines and just
33:45make it a little easier to read because it's shorter?
33:49Any suggestions for tightening up my implementation of get int?
33:53AUDIENCE: You can just return the value on the try
33:55function, when you're trying.
33:59You take the input x and then return x.
34:02DAVID MALAN: Good.
34:02We can just return x a little higher up.
34:05And let me correct folks as we go.
34:07It's not a try function.
34:08It would be a try statement, technically.
34:09A function typically has a parentheses and another one.
34:12In this case, it's just a statement.
34:14But we can do exactly that.
34:15I don't technically need the else.
34:17If I really want, I could do this.
34:19Right after line nine, I could return x here.
34:22Or recall our discussion of defining variables unnecessarily sometimes.
34:27Why define a variable here if you're immediately going
34:29to use it here and then never again?
34:31So we could avoid a new line here.
34:33And I could avoid even defining x explicitly.
34:37I could just say something like this.
34:39I could return int, input, quote unquote, "what's x?"
34:42I can do it all at once.
34:44Now, which is better?
34:46I don't know.
34:47I mean, again, this is where reasonable people might disagree.
34:50I'd argue that, on the one hand, we're tightening up the code.
34:53We're using fewer lines.
34:54It's easier to read, lower probability that I've made a mistake.
34:57On the other hand, it's a little more complicated to understand, perhaps.
35:01It's a little less obvious where I'm returning from.
35:04So I think arguments can be made either way.
35:06At the end of the day, what's important is that you've done this consciously.
35:09You've made a decision to do it this way or this way.
35:12And you can justify it in your mind-- not that your answer is, eh, it worked,
35:16so I left it alone.
35:17Have a good reason.
35:18Come up with a good reason.
35:19And that will come with experience and practice.
35:22Well, let me propose to you that we make one other refinement here.
35:25Suppose that you're finding your programs to be a little noisy.
35:28And it's a little obnoxious that you keep telling the user,
35:31x is not an integer.
35:32X is not an integer.
35:33X is not an integer.
35:34What if you want to make things a little gentler and just prompt
35:38the user again with the same words, what's x?
35:41What is x?
35:42What's x?
35:43Again and again.
35:44Well, you can do that as well.
35:45And it turns out that if you want to handle an exception in Python
pass
35:49but you want to pass on doing anything with it-- so you want to catch it,
35:54but you essentially want to ignore it.
35:56You don't want to print anything.
35:57You don't want to quit the program.
35:59You just want to silently ignore it, like
36:02if you're talking in a room full of people and it's your turn to talk
36:05and you're just like, pass.
36:07They're still calling on you.
36:08But you're not doing or saying anything more.
36:10Well, we can add this keyword to our code here.
36:13Let me go back to my program here.
36:15And instead of printing out again and again, x is not an integer,
36:19I could just do this.
36:20I could pass on handling the error further.
36:23I'm still catching it.
36:24So the user is not going to see a scary message even mentioning value error.
36:28My code is catching it.
36:29But I'm passing on saying anything about it.
36:32I'm going to stay in the loop.
36:33I'm going to stay in the loop and keep prompting and reprompting the user
36:36so now the effect looks a little something like this.
36:38Python of number.py.
36:40Let's type in cat.
36:42What's x again?
36:43Let's type in dog.
36:44What's x again?
36:45Type in bird.
36:46So it's just a little, maybe, more user friendly and that you're just
36:49reminding the user what you want.
36:50Maybe it's worse.
36:51Maybe it would be helpful to tell the user why
36:54you're prompting them again and again.
36:56It's not obvious.
36:57So it could go both ways.
36:58But, again, it's just another mechanism, now, for handling these errors.
37:02We use the except keyword to catch a specific error.
37:05But we don't have to handle it more than that.
37:07We can just pass on doing something further.
37:10Let me pause here and see if there's any questions now on try, accept, else,
37:15or pass?
37:17AUDIENCE: OK, yeah.
37:18No.
37:18I was just kind of curious, I guess, about the idea
37:22of when you were inventing with the get int function, for example.
37:27Because I'm noticing, obviously, going through it
37:29with the whole logic and breakdown of the entire function, while true,
37:33do this.
37:34But I'm just kind of curious in elaborating with the indentations
37:37for the code more.
37:38DAVID MALAN: Yeah.
37:39So the invitation is deliberate logically.
37:41Some languages don't require as rigorous indentation.
37:45You can use curly braces or other symbology
37:47to make clear what is associated with what.
37:49In general, any time you indent something in Python on this line--
37:54rather, anytime you write a code a line of code in Python that's here
37:58and the lines below it are somehow indented,
38:00that means that those lines are somehow associated with that first line.
38:04And, presumably, those indented lines should only
38:07be executed if the first line told the computer to do so.
38:13So, concretely, what does this mean?
38:14On line six here, we're defining a function called
38:17get in that takes no arguments, colon.
38:20Everything that's indented by at least four spaces
38:24hereafter is part of that function.
38:26Why?
38:26That's just the design of the Python language.
38:29Frankly, I think the designers got tired of seeing really ugly code in languages
38:33like C and C++ and Java that don't necessarily enforce indentation to this
38:40extent.
38:40So now it's baked into the language.
38:42And my chronology might be a little off there.
38:44But there's been many languages that are looser than Python when
38:47it comes to indentation.
38:48The indentation is meaningful on line seven too.
38:51Notice that because the while true is indented by four spaces.
38:55That just means it's part of the get int function.
38:57But notice below the while true statement, there is eight, there's 12,
39:01there's eight, there's 12 spaces here.
39:03And I'm just quickly counting the dots.
39:05That means that all of the lines I've just highlighted
39:07are inside of that while loop.
39:09While true means to execute lines eight through 11, potentially,
39:13again and again and again.
39:14And now, lastly, on line eight, because we have try and indented below
39:20it is line nine, that just means that what you should try
39:23is what's on line nine.
39:24And similarly, on line 10, below it, we have indented line 11.
39:29You should only pass when there is an exception of a value error.
39:33So the indentation just means what is associated with what.
39:37And once you get comfortable with that, you'll
39:38see that the indentation alone helps explain the logic of your program.
39:43And it has a wonderful side effect that for yourself the next morning,
39:47for your colleagues, your family, your friends, your teachers, your code
39:51is much more readable as a result. It's not one big mess of a blob of text.
39:55Other questions now on try, except, else, or pass?
39:59AUDIENCE: Yeah, thanks.
40:01Two question.
40:02Question one-- once you say pass, can the caller
40:08still learn anything about this era through a system variable or whatever?
40:14And question two-- problem set zero referenced some string methods,
40:19including is numeric--
40:21is it any different to [INAUDIBLE]?
40:27DAVID MALAN: Good question.
40:28So on the first question, if I'm handling the error in this way,
40:30the caller is not going to know anything about it.
40:32That's the point of my handling it, so that main or other callers don't know
40:37that anything technically went wrong.
40:38On the second question, is numeric is another function
40:41that you can call that can look at a string and determine
40:44is this, in fact, a number.
40:46I could use a mechanism like that.
40:48I could use a conditional.
40:50If this looks like a number, then pass it to the int function.
40:54And go ahead and convert it to an integer.
40:56That's totally fine.
40:57I would generally say that the Pythonic way of doing things is often,
41:02for better or for worse, to try things, hope they work.
41:05But if they don't, handle the exception.
41:08So other languages are more in favor of checking if, if, if, if, elif, else,
41:13and all of these conditionals.
41:15Python tends to be a little more of the mindset, eh, try it.
41:19But just make sure you're handling the error.
41:21So this would be the Pythonic way of doing it.
41:23Your way, though-- checking with the conditional, is it a number first?--
41:26is totally reasonable too, if you want to go that way.
41:29Well, let me propose some final refinements
Function Arguments
41:32to this program that really just kind of tighten things up,
41:34one additional step to improve the implementation of this
41:39get int function.
41:40Let me propose that we not hard code, so to speak-- that is type manually x
41:44all over the place.
41:45Let's make this function, get int, a little more reusable.
41:49Right now, notice that I'm just kind of using the honor system that, well, main
41:53is defining a variable called x.
41:55And get int is asking for a variable called x.
41:59But it would be nice if the caller, main,
42:02doesn't have to know what the call-ee is naming its variables and vise versa.
42:07So caller-- to call a function means to use it.
42:09The caller is the function that's using it.
42:11The call-ee is just the function being called.
42:14It would be nice if I'm not just hoping that x is the same in both places.
42:18So let me propose this.
42:20Let me propose that we actually add a parameter to get int, like this.
42:27What's x?
42:28That is to say, if main wants to use the get int function,
42:31well, then main should probably tell the get int function what
42:35prompt to show the user.
42:36Just like the input function, recall, that comes with Python, it's up to you
42:40to pass in a prompt that the user then sees when the human is asked for input.
42:45So how do I make this work here?
42:47I can go down to my definition of get int.
42:49And I can say, all right, get int is going to take a parameter now,
42:53called prompt.
42:53I could call it anything I want.
42:55But prompt in English is pretty self-explanatory.
42:57It means the message the user will see.
42:59And now, down here, when I actually use input,
43:02I don't have to presumptuously say, what's x?
43:05Because what if the program, the caller, wants
43:08to ask for y or z or some other variable?
43:10I can just pass to input whatever prompt the caller has provided.
43:15So now I'm making more reusable code.
43:18It still works just the same.
43:20I haven't changed the functionality, per se.
43:22But now it's a little more dynamic because now
43:24get int doesn't have to know or care what variable's being asked for,
43:28what's being asked for.
43:29It just needs to know what prompt it should show to the user.
43:33So if I now run this program down here, again, prompt number.py, Enter,
43:37what's x?
43:3850 still seems to work.
43:40Let's run it again.
43:41Let's type in cat.
43:42It still seems to work.
43:43And if I type in cat, dog, bird, or anything else,
43:46it will keep prompting me with that same prompt, making this code,
43:49therefore, all the more usable.
43:51Now it turns out, too, you can even raise exceptions yourself
Conclusion
43:55using Python's raise keyword.
43:57But more on that another time.
43:59So in the coming days, the coming weeks, the coming months,
44:01as you write more code in Python, you'll see that errors are inevitable.
44:05Sometimes they're syntax errors, which you've
44:07got to just fix if you even want to run your program at all.
44:10But they could be name errors-- for instance,
44:12variables that you meant to define but somehow didn't-- value errors,
44:15where maybe the user didn't cooperate and provided you with something that
44:19you weren't expecting, or a whole list of other possible errors or exceptions.
44:23But now, hopefully, you know how you can handle these errors
44:26and respond to them in any way you like.
44:29This, then, was our look at exceptions.
44:31And we'll see you next time.