 production of Python course, Sailor Academy. If this is your first time joining us, please start the course. I'll make sure the links are in the chat and the description below. We also have the full course you can take. And I will make sure, ooh, my apologies, everyone. I just had the live stream audio come into my headphone at the same time and it very much confused me. Anyway, I'll make sure the course and the program we're using Replet and our discourse discussion forums are available in the comments and they are available in the chat. And again, make sure you go back, check out our old videos and check out the course on sailor.org. But with no further ado, Dr. Sack, let's take it away and let's learn about some exception handling. Fantastic. So thank you, thank you. And so just wanna, well, we've already said it. I wanna talk about exceptions today. And so I wanna use this as a chance to maybe put a few things in context with regard to the unit. And just as a whole, because I encountered somebody yesterday when I was teaching them something. And I just wanna bring this point out is it's so important that when you're writing code that you learn how to debug small pieces of code so that you are really comfortable that you've verified that chunk of code basically. What I found with this one, and this happens all the time when I even say not to do it and students still do it. But just to have a mindset to think algorithmically, have a mindset to think in a methodical way so that if you, and don't assume that you sort of have a program that automatically works after you write a whole bunch of code. And what I was trying to get the student to do was sort of methodically step through a series of errors getting into sort of like the first level and the second level and to show that there wasn't just one error in the code, there were several errors. And how do you handle that? Well, the reason that he was kind of in that position in the first place was because he wasn't, he was assuming that everything worked, which we'll talk about that in a second anyway. So I just want, just as a piece of advice, whenever you get to a point where you've got like, maybe even when you're first starting out two or three lines of code, four lines of code, maybe an if statement, maybe a while loop, just have a hard to verify them so that if an error does occur, you know where the error isn't, and you start to eliminate errors in that way because you've verified code. And like, I know this section of code works, I know this section of code works, which kind of brings me to the next level of that. When you're first starting out in a programming course, you're not really taught initially to think about this stuff because it's just too much to think about. But I'd like to point out that there really are software design principles and there's concepts for software engineering. And not to be facetious, but I've gone to like student presentations, for instance, for software presentations, and they'll have a demo. And the demo, the professional demo is the, you know, that is the obstacle of eternity because getting something to work when you're demonstrating it to other people on a professional level is really, really an art more than a science in certain instances. But so students would kind of show me some type of software, maybe a chess game or some type of other, like a wild loop menu driven piece of software or something. And I could kind of see underneath the hood where they were going with their presentation and then they'd let you enter in data. And so that's when everything sort of, when you let the user enter in data, boy, anything in the universe can happen. So they'd have a message like, enter a number between one and four or something like that. And then I'd press five just for the heck of it, and then everything would just go like that. And my whole point, and again, not to be mean, but I'm just saying that you have to understand that when you actually do design real software that you don't have a lot of control over what people can do and anything in the universe can happen. So this is why when you're creating software, you have test routines and verification processes. There's a whole bunch of steps that are in order that an alpha and beta testing and so forth, so that you design what I call bulletproof software. And it's very important. Like I said, if you're using it in the basement of your own home, that's a different story. But again, if you're planning on going in a direction where you're gonna be really like designing stuff, you wanna be careful about things. You wanna be aware that you can't make the assumption that your software is going to work, I guess is what I'm saying. Cause you don't wanna do that. You don't wanna design the software for the flight control, assuming that it works could put a lot of people in danger that way. So just to bring, and the alpha and beta test, I just don't wanna go off on too much of a diet travel. I'll go to my next slide. But and again, I wanna remain agnostic as your teacher. But I'm just gonna say like, if you are running a software company and you're sending updates out like every five to seven days, your management is either suffering from obsessive compulsive disorder or it's just a terrible company. And that's just the way it is. That's what alpha and beta testing is for. And some companies, they get so big that to put people in a position where we have to find errors for them is kind of like you're in this continuous alpha phase of design, which is just totally unacceptable when it comes to this type of process. Anyway, so part of the path to creating bullet proof, and this is really why I'm trying to put in context for today is the idea that when you're writing code, you wanna kind of create a safety net anticipating what types of errors could occur in your software. And that's again, that's a science, but it's also an art as well. And you wanna design gentle software landings for your code, however that happens. And so therefore we need code for error handling. And you may need to design like a catalog of error codes, if this error occurs and so on and so forth. But again, I think as much as humanly possible, I think the real key is to keep your program threads running in the event of really any errors, any errors whatsoever if you can do that. And so the real goal is to avoid crashes. That can be the unsatisfying part of using software, right? It's like, you encounter some type of an error that the software can't handle and then what happens next. I mean, someone didn't really do very good planning. And that's all that boils down to. And that's just a question of how professional software companies wanna treat their customers. It's more of a customer satisfaction thing. But I don't wanna go all the way down that path. I'm just trying to put in context how important exception handling is. And it's something that it's hard to bring up in a class like this, but at least it needs to be said. And then you can kind of be prepared for other advanced software design concepts. So for us, for designing exception handlers, basically, just it should be clear to you in taking the course that the flow is very similar to sort of if else blocks, if else LF blocks that you've written before. And if you're comfortable with those, excuse me, those conditional statements, that's really what we're doing. We're writing conditional statements, but it's at a more sophisticated level because we're trying to identify errors in those conditional statements. So a try block is gonna let you test the block of code, basically, and if everything is good, then it gets executed and there's no worries. But if not, then the error is gonna get caught and some error will be caught. And then you will transfer control to the accept block, which ideally will in some way handle the error to whatever degree you as the designer would see fit. And then you have the optionals. The optionals are the else and finally blocks. And people call them, I mean, they're called optionals because if you have the else block, it's gonna execute in case there were no errors in the try block, which is good to have. And then there's a finally block, which is gonna execute independently of all the try, it's basically the rest of the code that you want to execute that'll always execute. And the word optional, I don't misunderstand what that word optional means. Optional means that in principle, you can design a try accept block without them and the try accept block will work. But I think when it comes to writing real code, you don't wanna leave them out. You wanna have else blocks and you wanna potentially have finally blocks as well because those are the chunks of code that are there to complete that safety net if I could put it that way. So we'll get into discussing all of these. Maybe it's a good time to come over to, let's say this slide, we'll come back to that one in a second. Let's get into this some kind of a replete of some kind. And so we should try and anticipate what types of errors could occur. And we'll just start really simple. I think it should be obvious what's gonna happen. There's obviously something wrong with a statement like this if you're writing code, if I haven't told you what A is, there's gonna be an issue. So all, I don't care what language it would be, excuse me, it would come out in the form of some type of an error, it might be a compile error, it might be interpreter error, it might be, but when we can characterize what the error type is, it'll help us. So if we go ahead and run this, we should see immediately that this is a name error. And this is the type of stuff you want to avoid. I mean, we don't care now. We're together in a class and it doesn't really matter. The world's not gonna end. The power grid isn't gonna go down. The telephone systems are still working. The planes are still flying. And so everything's fine. But when you see stuff like this, it can be, well, when you're testing, it's not a big deal. But if you have a program that's running and it does something like this, these red letters can be really, they're unnecessary. They shouldn't happen, is what I'm saying. And so, but before being able to sort of handle exceptions and handle different errors, we need to be able to characterize them and understand the universe of possibilities. And the universe is really quite large. All I wanna do today is just maybe talk about a subset of possible errors because once you get the idea, it becomes easy to characterize pretty much any, well, not, well, most any. Anyway, so that's what we call a name error. Another one that you're probably used to is if I said something, let's get that one off the list. If you do something like this, this is like a classic, this is a classic one, right? You wanna go ahead and take five and divide it by zero. There's gonna be a problem with that, right? You're gonna get an error that's called a zero division by zero error, a zero division error and error error. And so, these words are very, very important when you see them on the right side because they are honestly reserved words. They do identify that Python is taking exception to the line of code or the chunk of code that you're trying to execute. And then it's trying to let you know the exception that it's identifying, okay? And this will become important information for us in a moment. But right now, I'm just trying to, I'm trying to, the set of errors I'm picking are the ones that I've experienced the most with students really when they first start writing code. I think that's the biggest takeaway, the biggest deal. And so, name errors, division by zero errors, or if you would go ahead and maybe do something, let's say import the math, let's say, let's try another one. So let's, because we know the math library now, this is a good one to use. Maybe if I tried to take math.log of negative three, okay? And mathematically all should know that you don't wanna take the log of negative numbers. So, Python will take exceptions. We have what's called a value error. Again, a reserved keyword for the universe of possible exceptions that are sort of built into Python that Python is ready to look out for. And the reason is, is because you dropped a value into a function that isn't acceptable, it's unacceptable. So that's what a value error is. A value error is you called a function, you dropped something in and the function didn't like it. It didn't like the value. So that's a value error. Maybe if, let's see, let's just try a simple. Well, try something like this. Let's do this. What would happen? And this goes back to what I was saying a few seconds ago. So this is sort of a classic, you know, input a number. So you give instructions to the user and then you say, sorry about that, input a number. And oops, get rid of that. So make sure that runs, so we'll delete that one. So we wanna input a number. And again, classic thing would be like, okay, well, I'm being told to input a number, but I'm gonna input some text. And again, because of the fact that the input function is fine, the input function is happy with taking pretty much anything that you give it. The difficulty arises when you get that string back from the input function, that's not a number. Okay, it's not a number. You're gonna get a value error because when you float is expecting a number, now float is big enough, float is accepting and a float is robust enough to take, it could take a string, like that would be a three, a string three, quote, three, quote, and it'd be fine with that because that's what input returns text. And so float is emotionally prepared to handle data coming out of the input function that would be intended to be numerical. That's not the issue. The issue is if you tell the user to input a number and they input something else, and then you get about, so this is another version of a value error, okay? So value errors are typical types of errors that students oftentimes experience when writing functions, that they promised the function, they were gonna send one thing and then they sent it something else that it wasn't ready for, that it wasn't expected. So they broke their promise to the function and then the universe imploded. So that can happen. Maybe something like this, here's another one. So name error value errors, those are the types of things that you might expect would occur in an introductory programming course. Here's another one, try this one. I'm going to, maybe I intended to concatenate two strings together and then forgot to put the three in quotes or something like that. In this case, you'll get a type error because Python doesn't know if you want to add a value to three or if you want to concatenate a string to ASDF, okay? So the correction to that would probably be, you probably meant to do something like this and everything's good. So then you could go ahead and print. So that's a type error. Type error is when you're trying to mix and match types that they don't belong together. But if you can concatenate them together then that should be okay. And I love this, the timing of this example is so good. I got to share this with you, just blew my mind away. My son, who is eight years old, he likes to play Roblox a lot. And sometimes what will happen is that is that because people with higher privileges they'll be able to come into a game and they'll be able to do things that are not consistent with how the game is to be played in order to win the game. And so people in the chat box will start typing hacker, hacker, hacker, hacker like that. And that happened I think yesterday when he was playing and he said something, I just, I couldn't believe he said this. He goes, so he goes, so he goes, dad, what's hacker plus hacker? And of course, any normal person that you would run into the grocery store would say, well, it's hacker, hacker because you're concatenating those two strings together. The plus sign is not to add hacker plus hacker but it's to concatenate them together. So when he said hacker plus hacker I saw two strings and quotes like this. And then so the plus sign connected them together and I said hacker, hacker. And he said, that's right. Like that was his answer. Like he agreed that that was the correct answer. So I thought, oh my gosh, my eight year old son without even thinking about it knows understands string concatenation. You know what I mean? Just like he naturally understands that. Eight year old son is smarter than me. I was like, two hackers? Is that two hackers? But anyway, so probably, so this would avoid that type error, you know. And then, so again, what am I trying to do? Let me even pull out some more, maybe longer ones. Again, the type of thing that you might expect. Let me pick this out here. This looks like a good one. This is gonna be the overflow, okay? So I like this one because I don't like it. And I'll get into why I don't like it in a little bit later, but the idea here is that you're gonna take like e to the x. You're gonna take something and raise it to a power x. The power is 10 to the second, 30 second power. So e raised to the 10 to the 30 second power is a pretty big number. And it's gonna probably far exceed. It'll challenge your computing resources if you have a 64-bit machine. And so in this case, you get, it didn't like it. It didn't like raising that number to that power. And so what? So if you go ahead and run this, you're gonna get an overflow error. And I'll talk about this, not so much directly, but I wanna come back to this in a second because I don't fully agree that that's the right answer for this. But anyway, that's what it is. That's how Python handles it. So if you see like an overflow error, it means that you've challenged the resources of your, you've gone outside, something has happened where the numbers you're choosing are gone far outside the boundaries of what a computer could handle, okay? Another common one just to, I think, and this is an important one, by the way, especially this is the type of thing that might happen if you're, if you put the camera, great. Good going. And then this can happen when you start to learn about lists, you know? And when you have a list, obviously the indices for A here would be zero, one, two, and three. So there is no A seven, okay? And if you attempt to make reference, and funny enough, again, different languages will handle this type of an error in different ways. There are some languages that believe you as the expert programmer, if you put an index, you meant to do it, and you know what you're doing. And it'll let you actually put an index that might not be valid for like an array that you created, but it leaves you alone. And so, but this one doesn't. And you're gonna get what's called, obviously it's gonna be called an index error. So again, index error is a key word that we can use to characterize, to characterize, you know, errors that could happen for ordered containers, let's say. Okay, let's put it that way. Let's say for the unordered case, here's an example where you created a dictionary and you've got the keys. And again, I'm just trying to, really trying to just go through the whole course of these different data structures we've discussed and what types of errors that could occur with them. So here we've got a dictionary, you've got the key and the value, key value, key value. So key string one, value one, key string two, value two, key string three, key string four, value four. And then you attempt to make reference to the key M, which clearly doesn't exist on the list. I think anybody can see that. And so in that case, you'll get a key error. So I think even starting with though that possible list I'll discuss more as we go, we get deeper into what we're doing here. I think the real issue is that, is that this red stuff on the right side, okay? When you start to see this stuff in the interpreter window, in the command line window, the question is, can we avoid any of those kinds of errors? And what do I mean by avoid? Avoiding, identify them, catch them, do something, take some action that would save us the hassle of seeing. And the answer is, yeah. So let's just introduce a try piece of code, let's say here. And again, we've already discussed this. We know that there's gonna be some type of a name error because I'm gonna make reference. And so the structure of a try accept block is very, it's very straightforward and it's totally consistent with Python syntax, with indentation, with colons, everything that works for if, else's, everything that works for while loops, everything that works for functions, everything that, all the syntax that works for everything in Python is based upon, this little colon up here and then the indentation to define the try, what's called the try block or the accept block. Now obviously, even Replet right now, this little squiggly red line underneath is trying to basically say, no, no, no, don't do that, but we're gonna do that anyway. And we're gonna, if we run this, the whole point is that we get that error and we have an exception of some kind, okay? Something has taken place. Now, I'll get back to this in a second. We haven't really defined what the error is, but at least we know in the invent of the error, this is kind of a fudge in some sense because, and this is the way that you can write code sometimes almost subconsciously without really thinking through what the answer should be. So probably the more correct statement, even though we already know, because I told you about five minutes ago that this is a name error, that the, so you know that right now, but really what I should say here is like some kind of error occurred. You know what I mean? You really don't, all the accept does is that it knows something went wrong. And I'll come back to this in a second. That would probably be more accurate, okay? So just because you have the accept block does not endow you with the knowledge of the type of error that occurred. Now I'll come back to that in a second, but the only reason I put the first one in there first is because we know it's a name error and now you put the message, but it really could have been any kind of an error. So probably the more accurate measure would be some kind of error occurred. So just, you know, note that and we'll come back to it. So that's a try accept block. So maybe what we'll do is something like this instead, right, where we've got the accept and now what we're gonna do is we're gonna make the exception dependent on the actual type of error, okay? And now, and this is a big deal. It's a big deal because you as the expert program now are actually attempting to identify using those Python keywords, identify the type of error that occurred and therefore take some type of action based upon the error that occurred. In this case, it's pretty mundane, there's nothing going on, but the message is clear. The message is correct, okay? Is that when the name error occurs, the variable, just the reason it happened is because the variable wasn't defined. So now I'm being very specific about what the name of the error is and then otherwise, if something else happened, we'll have another accept in there for something else. So if I said something like A is equal to three plus going back to the other example that we said a few seconds ago, that if you run this, some kind of error occurred. And again, just it depends on why you're writing this, why you're, what your intent is, but you wanna be clear. And also one other thing, by the way, is that when you write this code, the order in which the exceptions are addressed is exactly the order that it will be addressed, okay? So if you have a list of exceptions, the test is gonna go sort of from top to bottom sequentially. And the first exception that matches your issue will be the one that's addressed. And that'll make a little bit more sense in a second as well, but that's the main idea. So I think part of the art of designing exception handlers is A, being able to identify all the possible errors and then taking the right action based upon that set of errors. And again, this is exactly why you have alpha and beta testing is because especially when you start writing very, very large software packages in large companies where large numbers of people putting large things together. And we just have to have some methodical series of steps that allow you to sort of coalesce all those pieces together and so this is the first basic step at the 105 level of how you begin to even broach the subject of writing software like that, okay? And so again, so or you could have something like this if you just come back to, you know, it's another example. Clearly, something isn't going right, but it's not a name error. It's obviously not a name error. That's not the issue. All right, I think there's enough said about that. Let's see here. So when you write handlers, okay, when you go ahead and write handlers, you're allowed to make the list pretty much as long as you want to, you know? And so in this case, you know, you'd have a value error. If there were a value error, there could be a name error. And so the value error we said already is, you know, is gonna be related to when you made a function call and the function basically spewed, it said, I don't want anything to do with this. So now what you have are blocks of accept clauses basically, each one is servicing some different, you know, possibility based upon this allowed set of keywords that Python, you know, has tried to come up with a, you know, as exhaustive as possible, tried to come up with, you know, a list of cases for exceptions. And then if not, then you as the software designer get to, you know, design your own handlers for whatever, you know, cases you would want to design for. So this is just, so my point is that, is that you can go on and on and on with accept clauses. There's no stopping it. And you can, you know, I mentioned this briefly and it's mentioned, definitely mentioned within the course is that, you know, you don't have to sort of unravel every possible exception with keywords. There's syntax where you can have an accept with many possible errors listed, you know, like as a tuple basically, as a tuple. Again, I'm not gonna go there today, but there's different ways of addressing multiple errors, I guess is what I want to say. And that's probably more the direction that I want to go in as we go deeper. But then, so that's the try and accept. If we add on the, like a try accept else type of a thing, in this case, you know, you have A is equal to hello world and there might be an exception and there might not be. But if there isn't, then we would want to, I guess, you know, take, well, let's take this out and just go back to the old days, you know, with something like this, you know, so an exception occurred. But if A is well-defined and there was no error, then you want to possibly service, you know, the exception and do something opposite to what the accept was doing. And in that case, you would use something like an else. And this wouldn't be code that would be running for all cases. This would just be in case the error doesn't occur. And so if you do that, then you'd see the value printed out and then the else actually executed. So in some sense, as I said before, you know, the structure of try accept else blocks, you know, very similar to what you've already done for if else, so it should be like a really natural, it should be a very natural step to, you know, write code for handling exceptions. I mean, again, at the basic level. All right. For the finally, you know, we could take a finally or so and for a finally example, in this case, if you do something like this, then we've, you know, we're already set up for like the 18th time, you know, print A. I think you're all getting that at this point. It's gonna be some type of a name error. And so the exception occurs and we handle the exception and that wasn't really handled in the brightest of ways, but at least it lets you know an error occurred. And then with finally, so, but the whole point is that you're not getting that red stuff thrown out to the screen. You know what I mean? That's really the thing that we want to avoid this long stuff that gets thrown out and we don't want that, you know? So that's what this print statement does. And then of course we go on and then execute, excuse me, anything that's in the finally call. So in this case, the error did occur and then we moved on to the rest of the code that should continue executing. And again, that's kind of, you know, the finally is there for the crash proofness, you know, that if the program can continue, it should continue. And that's really like the way that you wanna design software. And there have been some really good packages out there that actually do that extremely well, extremely well. And like I said, but I think that's the way that you wanna design your code. And I know, again, like in an introductory course, that isn't usually like the most important component. I think that like when you're first learning, you wanna get the syntax, of course, wanna get the basics, you know, one sort of loops, conditionals, functions, methods, you know, objects, these types of things. And then of course, we kind of, we wanna grow out of that infantile state basically to assume that everything that we write is going to work, okay? Like probably that's actually not the case and for more, you know, complicated pieces of software. Again, you know, with millions of lights of code and documentation that would go from here to the ceiling, you know, those are the places where this really matters. And so it's hard to, it's hard to impress in a course like this, you know, the importance, the criticality of understanding how to write code like this. And it's not that big of a deal, but it is extra work. Documentation and exception handlers, you know, are more work, you know what I mean? They're more time consuming. And sometimes when like, when you're just in a mode where you're like writing software, you just wanna get something to work really quick and you type it up. And if it's just for you, it's a onesie or twosie, it's not that big of a deal. But as I said before, you know, who knows what you're gonna do with this course when you move on, you know, you actually may be interested in, you know, becoming a programmer or something like that. You just wanna be aware that up until this unit, that's not how things work professionally, I guess is what I would say. If I could put it that way, you know, cause you have to learn, you have to get, you have to walk before you can run. I guess I would say that, put it that way. All right, so let's imagine that you're going to write a real exception handler. I mean, you're really going to come up with an outcome, design an outcome for your program if a certain type of exception occurs and you want to have this kind of soft landing or allow the program to continue. I just, I wanna show you some elements that I think could turn out to be quite useful when it comes to protecting from, you know, let's say numerical, you know, numerical fatalities, potential fatalities. I think probably a few are the best and there are others. Like I said, when you design code, you'll work with people to come up with error codes, basically, you know, this number means this, that number means that, you can go a big matrix of everything in the universe that could go along. And, but I think as a start to that, it's good to remember that the value none is a valid Python keyword. So if you have code and you catch an error, you know, you may want to return a value like none from your exception handler because on the other side of it, like if you return from some routine of some type and you can write your code so that if this value is equal to none, then you know something went wrong, right? And none sometimes will separate itself from the other set of, it may not, I'm not saying there always does that, but maybe you were expecting a string or a dictionary or a, you know, or whatever, you know, some type of data type or a number, something. And then you see that you got a none that returned and because your exception handler ran, then you can put constraints in your code to say, you know, if value returned none, then do this, this kind of a thing. And so it's kind of like a path to a soft landing. I want to alert you to something else too. Again, this isn't something that, again, it's like, there's so much to talk about. It's almost like in my universe, you know, I think everybody knows this, but then I realized probably not, you know, not everybody knows this, but when it comes to like representing numbers, there are values, there are valid numerical values for indicating positive infinity, negative infinity and something called not a number. And, you know, what is that? So positive infinity could mean, for instance, like that e to the something that I just showed you a little while ago, e to the 10 to the 32nd power. And in those circumstances, that would be, when you start to go outside the boundaries of the positive numbers that your computer could represent, that would be a positive infinity. Or if you go in the direction of a negative number, then you could go towards negative infinity. If just went to, if the number went to negative, or if it results in something that isn't really defined, like zero divided by zero. Although again, I would even, you know, mathematically, I would even caution, you know, about the zero over zero case because if you've ever taken a calculus class, again, it's not, if you have, I'm just speaking to probably a small set, you know, you have things like L'Hopital's rule that allow you to handle instances where your numerator and your denominator are approaching zero. But if it does turn out that you get a form like this and you can't handle it initially, that zero over zero would probably fall into the realm of not a number. And so when you have instances like this, let me just show you that, you know, the, you know, you could, the rules for like infinity, for instance, if I were to say something like three plus B, you know, would give you the infinity back. So infinitely plus three is equal to infinity. Or if you tried to take infinity plus infinity, you know, that's still, sorry about that. Let's see, that was B, case sensitive. That would give you infinity as well. Or B plus D, if you tried to add infinity to not a number. Again, I don't know, so you get not a number. Again, I don't have time to go into the, you know, sort of the algebra of all the rules of not a number and infinities. If you know them great, if you don't, it's not a big deal. But here's the deal, that if it gives you a way to create values that would go outside the realm of values that your method could return. And I think that's important to know. Like, so for instance, maybe you have a function that's trying to find a value on a list and it doesn't find it. Well, then you might return potentially, if you agree that you're just gonna use positive indices, you might return to you to use a negative, return a negative number. So sometimes methods or functions and part of the error handling process in terms of the exception handling process, it's a good idea to think of values that you might wanna return that wouldn't be in the set of things that you were processing and to be able to use that as part of your error handling. And I'm just throwing these out here as ideas because they can be useful that, you know, they set themselves apart from a lot of calculations that you can make. And again, you know, I don't know where to bring this up in the course. It may have been best for me to bring it up like when I was introducing floating point numbers, but it's so early in the course to bring up the concept of infinity, you know, at that point that I just didn't, I didn't feel that was the place. This unit, I feel like it's the place where this is good information to know if you really ever have to like design an exception handler because you'll find that you're always looking to return something that's outside the set of realm of possibility of things that would have been computed. So these could be useful values. So I just wanted to, you know, say that and make that a major, major point because that's part of, you know, writing error handlers in general. Let me grab this piece of code and have a discussion now about, just about exception. So we'll go back to our division by zero error. And the, when it comes to this, this is really a Python thing or it's a language thing is that you as the language design, people if you're trying to design Python and you are trying to characterize the universe of all possible errors that you would want your language to have built in to be able to catch. And you would do it in a hierarchical way. You would, again, if I left you alone on a desert island take my word for it, that's the way that you would do it. And so the error catching has to be hierarchical because it's up to, you wanna leave up to the programmer the sort of the universe of possibilities for a given type of error. And so in the Python hierarchy, there are what are called arithmetic errors. And underneath arithmetic errors, you could have various arithmetic division by zero. You could have overflow, the one that I showed you a little while. So if you were to run a piece of code like this at first glance, this is obviously a division by zero error. Okay, but what I said before was that when you process the exceptions, just because of the way a sequential processor in a language has to work, just the way if else clauses work, by the way, if else eliffs work is that you sort of, the first thing that you see that you satisfy to be true is the potentiality that you execute. And then once you execute that potentiality, you're really not gonna pay attention to the other ones. And so that's how the except hierarchy is going to work in terms of the code is that if a division by zero error is gonna be arithmetic that you're most likely going to see this one first. So that would be my guess if I had a chunk of code like this because arithmetic errors encompass a wide range of errors. Now, if we go like this and we put this, for instance, second, like so, then you'll see the zero division by zero error. Okay, because the zero division error is a subset of all possible arithmetic errors. So like within the course, and this is what I was kind of showing, let me come back over here for a second. There's reference that's made to this webpage because this is kind of like the Python documentation for Python three. And you should know, if you haven't ever visited this site by this point in the course, you really should. Again, it's not necessary to make the course work, but it gives you on a more technical level how Python works in general. And if you go, and this page is listed within one of the pages of the course and it gives the hierarchy. It kind of, the largest, so this will become so much clearer in the next unit. But again, everything in Python is derived from objects defined by classes. And so the largest exception class is gonna be the base class. It's gonna be the base exception. So you could search for a base exception and basically you're looking for pretty much anything underneath the hood, which isn't gonna be very helpful. So then what you try and do is sort of methodically, hierarchically, break down to whole bunches of errors. And then as you come down to this list, you'll see pretty much exactly what I just told you is that in the set of arithmetic errors, you can have several different types of errors. And I just wanna make you aware, when I used the word hierarchical, this is what I'm kind of picturing in my head. And in terms of just having a process for understanding the universe of possible errors that could occur. Again, as I said, if you really start to do this stuff, you may find something that's not on that list and you may have to design something separately to do that. But you have all the hooks in a language like Python to do that. And then the second thing in terms of execution, it's so important to recognize that there's an order just like as with if else classes. I can't emphasize this enough is that the ordering of how you specify these exceptions. Now you can see why if I put the arithmetic error first that that's what's going to happen. So I think like some total, I can't sort of just for an introductory discussion, I can't think of too much that I also that I want to say, I just wanna get across the importance of exceptions and try else finally and accept understanding those key words. Understanding at least some of the errors that you should expect would happen at an introductory course. And then just in terms of the hierarchy of how you arrange your accept statements based upon these predefined keywords that define the kind of error that occurred. And then lastly, just the idea that when you design your accept clauses, they're gonna be pretty much executed in the order that they're encountered. And again, that should appeal to your understanding of if else and LFs, okay? So I think with that introduction, I think it's probably sensible to maybe play around with some examples just to kind of make sure that, you know, we're good with all of this, just going back to a simple, maybe a simple try example, try accept. You know, maybe we wanna write a function that does something like this. So this function is going to, and again, I reserve the right to use the math library because again, that was visited many eons ago in the unit where we talked about functions and so forth, which kind of introduced the notion of how to import something, import a module, the math module and all, or a large number of methods that can be called from that module. One of which is the square root. And so if you enter the number and everything's good, well, then we're just gonna return under the try condition, we're going to return the square root of that number. And then otherwise, what we're gonna do is we're going to, you know, print something else. Like if it's a value error, the input argument, for instance, would be non-negative and then you would return, in this case, a negative one. And so if we compare and contrast, let's say this versus, you know, taking the square root of negative two, I'll make mention of something else in a second. Is that the, so here's where if we didn't have this, you know what would happen is, you know, if I just said, let's say, maybe you don't, so we'll do it, maybe you don't. If I say something like math that square root negative two, okay, then you're gonna get this issue, you know, that's gonna say, hey, you can't do something like this. So when you, I just wanna point out that that there is a CMath library that handles complex numbers. So it is possible to take the square root of a negative number, okay? But in the instance where you try and take the square root of something, you have to have something in place. Now, the return function is going to, is gonna return a value of negative one. And so this is where I'm saying, well, when you return something from your exception handler, that you're going to return a value that isn't in the spectrum of possible answers the function could give you. So when you take a square root, it usually means for the function, it's gonna mean take the positive square root because there are always two square roots. You get a positive and a negative, but it'll just return the positive one. And so it would be safe as part of your exception handler to return a negative value because that isn't something that you would expect to get from the function itself. Let's try another one. Over here, I, again, going back to making this point to get about not a numbers and minus infinities and handling values that wouldn't be what you would want, let's say, from a division, okay? And so there are degrees of infinities. There are degrees of pathological, numerically pathological behaviors. And so in this case, if we tried to divide three by four, you'd expect that you would get a value back. But like if you tried to divide zero divided by zero, that type of division by zero, it wouldn't be, you'd want to characterize it. Like it wouldn't be necessarily, that wouldn't fall within the potential of like an infinity. It would be really a not very well-defined number in the absence of any other information. And so in this case, you actually might wanna go through the work of returning not a number. Otherwise, if you had the instance where the numerator was less than zero, you'd be taking like negative five divided by zero. And it really, that wouldn't fall within the realm of not a number. It really probably would be more like a positive infinity approaching a positive infinity. And if you took a negative number and divided that by zero, then you'd go ahead and get negative infinity. So now what we try and do is we try and handle these different kinds of divisions. Or if I said, if I wanted to write something like this, and honestly, whenever you, if you really wanted to, if you really, whenever you pull out that division sign, you really want to make sure that you've got those numbers can't well characterize it. You know, a program killer, like an introductory program killers is when it's assumed that the denominator isn't equal to zero when it actually can be. And so you really, whenever you pull out that division sign, you always want to watch that denominator as closely as possible, because stuff happens. So again, so these are various, oops, sorry. Made a mistake there. That's true. Let's say negative five divided by zero. Okay. And so just different cases that you might want to characterize your division by zeros. You don't have to do this. I'm just trying to give you examples of, what I'm really, the point of this example is really to demonstrate to you that there's a whole bunch of stuff that can go into the exception handler, for further analysis of what the error is. So, I know I started out with these one-liners because I'm trying to get the point across of like, try accept Elson finally. But usually, if you're really writing these things, you can have quite a bit of code in the accept block depending on what you're trying to accomplish. Okay. Let's do another one, just a natural one that you might encounter and just go on and on and on and on about this. So, here is an example of using else. Okay, and the point of this code is that you're always wanting to return something if you can keep the code going. The goal is always to keep the code going if you can. If it's sensible, if it makes sense. If you have to stop the program, then so be it. But if you want to keep the code going, you've got to have parameters that give you the ability to have this soft landing that I'm talking about. So, if for instance, for some reason, I'm gonna try some code that would call this function. I send a list that has only zero, one, two, three, four as the indices and then the list, again, this is probably, I would have to say, one of the most common errors, again, are index errors when students first learn how to make lists, how to create lists because the danger is that you're trying to make reference to an element that doesn't exist on the list. The index doesn't make sense. So, in the case of an index error, yeah, well, definitely if you want to print the message, but if you wanted to keep the, you know, to keep main going, what do you do? Well, you wanna return something because in the else condition where there isn't, what's happening is that there's a minus 99 that's being appended to the value of A list. So, if there is no error, if there's been no error, you're gonna return something that's a list. Well, what do you do if you get the error? You know, you might wanna return a none because it's kind of like a null value that you could write extra code down here that would say, hey, if none, then do something else. It's very typical, like, again, we're going back to, for things like memory allocation, big, big, big, big deals that you always wanna check to see whether or not the operating system gave you a memory. And when you check for the file, you wanna make sure that the file actually exists. You know, these kinds of things, you know, you can get more information or you can give more information from your, you know, from your exception handler. Okay, so in this case, the index error, trying to index, trying to access indices that aren't on the list, and the program ran fine. Okay, there's no red text, it didn't crash. The program is ready for the next thing. I think that's a really good way to design code, okay? And then maybe one more, I guess, yeah, I'll try this one down here, just to kind of throw them all together in the time that we have. So in this case, there's gonna be some type of op test. And so now I've kind of thrown them all together. And this would be, you know, similar to, you know, what you would want to do if you wanted to integrate everybody, you know, bring everybody into it, to try the optionals, try accept, and then the optionals else and finally. And everything, something's going to happen in every one of these cases, okay? In the first case, we're going, well, the try is just gonna try and allow you to input a number, but now we're really, really gonna watch out, make sure that, you know, if we don't input a number, what are we gonna do? Well, if there's no error, then we're going to, then we're going to take that value, add three, two and divide it by five. And then the finally, and this is the key, I think, this is the key, you know, that we probably end with, you know, just given the time is that, the key is that the finally is going to execute under all circumstances. So the finally returns something under all circumstances. And in the first case, if the error would occur, well, it's just gonna return not a number. In the second case, if our error doesn't, it's gonna compute this. And then finally, that's what's going to get returned. So if we run this and, you know, I input the number of four, nothing wrong with that. Everything's good. Then I'm just gonna take four, add three to it, take seven and divide it by five. If I do something like this, oops, sorry, what did I do? If I do something like that, okay, the error is that you say, well, you didn't input a number, but now a value also gets returned. So this is the kind of structure that I would say that, you know, if you were just doing it for yourself, it could be kind of a pain in the neck because, you know, if it's a onesie-toosie kind of a thing, the worst that happens is you get that stuff out to the screen. But again, in the event of somebody else is using your code, okay, then probably you wanna be, you know, a little bit more in the camp of people that would be designing soft landings. And that's the whole point is that there's really, I'd say the three major things are knowing the keywords for what types of errors you're interested in detecting. And then being able to write the hierarchy in terms of sequentially dealing with all the possible except possibilities. And then being able to sort of arrange the try, except else and final ease, given that hierarchy so that you have a nice smooth bulletproof piece of code. So I think I'll probably stop there because it looks like we're on time. So that worked out well, almost perfectly. Yeah, that was great. I'll give a little bit of time. We haven't had any questions as of yet. Well, that I couldn't answer anyway. So we'll give it another second. And while I'll just mention that I saw, Python came up this weekend and I found out that Netflix does a lot of their backend coding on Python, which I found interesting. Yeah, probably so. And it's a great language for development. And then you got to get for the deployment. So again, so for this course, it's like this is all for development. What IDE would you want to use to develop code on and stuff? We picked this one because it's easy, it runs on the web. You would use something a little bit nicer. And then you got to go from the Python code to some executable system that could be deployed independent of the IDE. And so yeah, so there's lots of hooks out there to be able to go from point A to the final place. Because right now this is only interpreted. But yeah, I mean, I think a lot of people these days are doing their development on using Python because it's just so seamless. And there's so much, there's just so many modules out there to do so many amazing things. It's outrageous. It's outrageous how the community of Python building and Python developers has just exploded into some of the coolest tools that you could pay a lot of money for it elsewhere, like OpenCV for instance. OpenCV is like a computer vision type of module. And the stuff in there is ridiculously powerful. It's close to bulletproof a lot of it and it's free. And it's actually free. So yeah, Python's great, you know. Well, I think we're good here. I think we should definitely say, well, thank you for, as always, Diver Sack for helping learn us. We'll be back next week at the same time for the unit 10 wrap up. If you haven't caught us, if you haven't caught up yet, make sure you go check out the other videos. If you've watched this whole video and you're like, I'm confused, go and watch those and take the course. All the links are in the description below and we'll see everyone again next week.