Handling Errors the Graceful Way in Python
This is a modal window.
The media could not be loaded, either because the server or network failed or because the format is not supported.
Formal Metadata
Title |
| |
Title of Series | ||
Number of Parts | 112 | |
Author | ||
License | CC Attribution - NonCommercial - ShareAlike 4.0 International: You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this | |
Identifiers | 10.5446/60805 (DOI) | |
Publisher | ||
Release Date | ||
Language |
Content Metadata
Subject Area | ||
Genre | ||
Abstract |
|
00:00
Functional (mathematics)Crash (computing)NumberGoodness of fitMedical imagingComputer fileException handlingCausalityExistenceBus (computing)Programmer (hardware)Multiplication signFood energyPhysical lawArmSoftware engineeringCoefficient of determinationCASE <Informatik>Library (computing)State of matterBoolean algebraFormal languageMessage passingProcess (computing)Confidence intervalDivision (mathematics)Set (mathematics)Different (Kate Ryan album)Spontaneous symmetry breakingComputer programmingCore dumpGroup actionError messageBlock (periodic table)Game controllerOperator (mathematics)Virtual machineSubsetNatural numberVideo gameArrow of timeGodBit rateTrailLatent heatQuicksortThermal radiationType theoryMathematicsGame theoryRight angleMetropolitan area networkWebsiteData storage deviceOrder (biology)Logic gateSubject indexingObject (grammar)Social classPort scannerInformationForm (programming)CodeRun time (program lifecycle phase)Similarity (geometry)Buffer overflowInheritance (object-oriented programming)Interpreter (computing)Electronic mailing listSoftware developerSoftware bugRepresentation (politics)DataflowWordBitLogicImplementationVulnerability (computing)Dependent and independent variablesFault-tolerant systemPoint (geometry)MereologyEndliche Modelltheorie
09:08
Error messageException handlingType theoryMessage passingTypprüfungClient (computing)MereologyCondition numberString (computer science)Functional (mathematics)Statement (computer science)Declarative programmingDivision (mathematics)Letterpress printingLatent heatNumberElement (mathematics)Subject indexingCodeBlock (periodic table)Group actionObject (grammar)MathematicsDifferent (Kate Ryan album)Formal languageCASE <Informatik>Single-precision floating-point formatTupleSeries (mathematics)Interpreter (computing)DivisorLevel (video gaming)QuicksortoutputLine (geometry)Moment (mathematics)Multiplication signState of matterCoefficient of determinationPhysical lawFood energyBit rateSource codeOrder (biology)Internet forumComputer configurationTriangleHypermediaSummierbarkeitGoogolAutomatic differentiationSubsetTablet computerText editorFerry CorstenWritingExistencePoint cloudRight angleIdentity managementVideoconferencingAreaPoint (geometry)Metropolitan area networkFigurate number2 (number)Graphics tabletEvent horizonWebsitePrice indexGenderReading (process)
18:16
OvalInterior (topology)Order (biology)Right angleMultiplication signIntrusion detection systemNumberError messageComputer programmingBlock (periodic table)Exception handlingComplex (psychology)Object (grammar)Message passingCASE <Informatik>Subject indexingComputer fileSoftwareFunctional (mathematics)Software engineeringData centerReading (process)Parity (mathematics)Server (computing)Form (programming)MereologyCodeLetterpress printingSeries (mathematics)Level (video gaming)Division (mathematics)Tracing (software)Game controllerGraphical user interfaceDataflowRemote procedure callStatement (computer science)Group actionNetwork topologyCoefficient of determinationAuditory maskingGoogolMedical imagingArmInstance (computer science)Optical disc driveElement (mathematics)Matching (graph theory)Ferry CorstenAxiom of choicePhysical lawWebsiteBitPhysical systemMaxima and minimaMathematicsGoodness of fitBlogProcess (computing)Online helpPlanningBoss CorporationMountain passState of matterTriangleFormal languageFamily
27:25
Gamma functionTraffic reportingGoodness of fitNetwork topologyTerm (mathematics)Moment <Mathematik>Lecture/Conference
Transcript: English(auto-generated)
00:07
Hi, everyone. I hope I'm audible to everyone. My name is Sriya Bansal and welcome to my talk today where we talk about handling errors the graceful way in Python. Before starting,
00:24
I think you already got introduced to me a little bit but I'll just go over it again. My name is Sriya Bansal and I'm currently working as a software engineer at Microsoft and I think this is my third PyCon I'm speaking at, virtually only this time though,
00:41
I couldn't attend. So, let's get right into it. So, what we are going to talk about today is the very important part that every software developer here, right, would agree that errors are the bane of a programmer's existence, right? Things rarely go planned in the world
01:04
of software engineering. You write an awesome piece of code, you're ready to execute it, right? You build a very powerful machine learning model and then poof, right? Python throws an unexpected error ending your hope of quick code execution. So, I think it would be wise to
01:24
conclude that errors are unavoidable while you are writing code. And in a way, it would be also wise to say that dealing with bugs and errors, that's what actually, you know, builds your confidence and in the long run, it also teaches you some valuable lessons along the way.
01:45
Hence, this tells us the answer to our very first slide, which is why do we do error handling, right? Why is the very concept of error handling required? Now, we'll go a little bit deeper
02:01
into it, right? And we'll talk a little bit in detail about what exactly error handling is, what are errors, right? How do we deal with errors, right? And what are the different situations we should keep in mind. So, we know that a Python program basically terminates as soon as it encounters an unhandled error, right? And these errors can broadly be classified
02:25
into two classes. First, we think of that as syntax errors. And second, we think of it as logical errors, right? Or we call it as exceptions, which is what the talk is about today. When we talk about syntax errors, these are errors which are caused by, you know,
02:42
when you're properly not using the syntax, wrong way of declaring the errors, right? You don't keep in mind certain syntax, right? Or basically, you're not understanding the syntax and that's what Python wants you to do. That's what we consider as syntactical errors, right? But then we also have something which are known as logical errors. So, what happens is,
03:03
many times a program can result into an error after it is, you know, when it is running, right? And even though it does not have any syntax error. Such types of errors, we think of it as an exception, right? They are called as runtime errors. And Python itself, Python
03:21
library itself has defined a lot of built-in exceptions, right? For example, we have assertion error, we have floating point error, overflow error, name error, and the list is very long. And whenever these exception occurs, the Python interpreter basically stops the current process and passes it basically to the calling process, right? And it keeps on passing it to the
03:46
calling process, the error keeps on percolating to the calling process until and unless the error is handled. And if you don't really handle that error, right, the program will simply crash. Let's take an example. Let's say you have written a program where a function A
04:01
calls function B, function B calls function C. So, if an error occurs in function C, right, and it is not handled in function C, it passes on to function B, and then if it's not even handled in function B, it passes on back to function A. So, the error is going back to the functions which are calling those, right? And if you don't handle that error at all, an error message is
04:24
simply displayed, right? And your program comes to an unexpected halt. So, that is why Python, just like any other language, provides us with the provision to handle exceptions, as you might have seen in other languages as well, right? And in other languages, you might know it
04:43
as try and catch block, whereas in Python, I really like this, actually, we call it as try and accept block, right? So, try block basically allows you to write the code that is going to have error, right? If there is a certain set of code that you think that might come across
05:01
some errors, right, that piece of code which is vulnerable to error, the better word to say is, is basically goes into the try block. And the code, right, which, so, for example, if any exception occurs inside the try block, right, the accept block is basically triggered in which you can handle the exception, right? Because as now, because of this,
05:21
because you are into the accept block, the code will not halt, right? It will not go into the halt state, right? But the flow of the accept block will basically take care everything that you want to take care of. So, here is a small syntax representation for that. The critical operation, right, which like I said is prone to error and which can raise an
05:44
exception, right? It goes into the try block and then the code that handles those errors, that handles those exceptions goes into the accept block, right? So, we thus choose what operations to perform once we have actually caught the exception, right? So, there's like a block of code which, the responsibility for which is just to take care of the exceptions
06:05
which come, you know, in a vulnerable piece of code, right? So, trying an accept, remember, goes hand in hand, okay? That is the syntax to write this, to write and to use both of them together. If you're just simply writing try block or if you're just simply
06:20
using an accept block, you can face errors by choosing that kind of implementation. So, let's take a very simple example. I think the best way we can go ahead is to just take examples and understand. So, here, there's an example where we have a function where we are dividing two numbers, okay? So, Python interpreter will basically raise an exception,
06:41
right? When we basically try to divide a number with zero. That's basic mathematics. So, when it does, we can take some custom action right on it and we can do something in case we encounter an error and we can handle that in the accept clause, okay? Also, understand that whenever a Python interpreter basically raises an exception,
07:02
it is in the form of objects, okay? So, whenever you have an exception, the exception always comes in as an object. Here, we have taken that object as e, okay? And it is in the form of object that basically stores the information about the exception, right? What kind of an exception it is, right? And what kind of message.
07:23
Like earlier, we talked about we have so many exceptions, right? We have an overflow exception, name error exception, assertion exception. So, a similar type of exception will occur when you will try to divide a number with zero, okay? And also, with every exception, right? Every exception type. So, like I said,
07:41
there are a lot of exceptions. And all of those exceptions basically in Python, they inherit from a base class which is exception class, right? So, whatever exceptions you have, right? They all are inherited from the base exception class. So, now, in this example, right? When we were dividing two numbers, right? Python
08:02
interpreter will basically raise like an exception over here whenever you will try to divide the whenever you will try to divide 10 by zero. So, the previous example that we just saw, right? It did not mention any specific exception, right? It was just a basic base
08:21
exception class as you can see over here, right? Here, we did not have any specific exception that we're trying to catch, right? And that is not a very good programming practice, as it will catch all the exceptions, right? There are a lot of exceptions and no matter what exceptions comes in your code, it will just simply catch all of them, right? And it will
08:41
handle every case in the same way. So, no matter what kind of exception occurs, it's going to show you the same message for all of them, right? Again, that's not a very good exception practice. For every specific type of exception, you should have a specific way of handling all of them, right? And with that, the next thing that comes is how do you catch specific
09:03
type of exceptions? So, here, the syntax for that is actually very simple. A try clause can have any number of except clauses to handle different types of exceptions. However, only one kind of one of them will be executed, right? In case any exception occurs. So, although you
09:22
associate multiple except blocks with a single try block, not all of them are going to be executed with the try block, okay? And only one of them will get actually executed. So, what we do is we actually create a tuple of values. So, you can, I would say, catch a single exception also. For example, except value error, you can basically expect just that kind of exception also or you
09:46
can have like multiple exceptions clubbed together, right? And you can handle them together in a except block as well. So, in the first example, you see except value error where we are just taking care of one exception. But in the next one, we are taking care of two exceptions. And
10:02
in the last one, any error apart from the above three errors are basically taken care of in the last except block. So, this is a good practice, right? To basically catch specific type of exceptions and to handle them and to segregate those error scenarios separately, okay? And yes, you can have as many except blocks as you can, right? You can club a lot of them
10:26
together also and you can basically have one level of segregation for all exception blocks as well. So, now again, let's take a look at the piece of code over here. So, in this code, what you will see is, again, we have the divide function, right? And in this code, what you will see is
10:42
that the exception that is being raised, it totally depends on the input that the user is going to give, okay? So, if the user basically gives a value b in the input, so any value of a is acceptable, right? But in the input b, if you give a value zero, right? The Python interpreter will
11:00
basically raise a zero division error. So, it's not even going to read the rest of the code, which is the print statement, an array declaration, and then a print statement again. It's not going to read all of them. It's just simply going to go to the zero division error and your code will simply terminate at that point, right? But what if you give valid values of a and b and then, right, you come to the declaration of the array a and then you do print a of four.
11:27
So, in that case, you're going to go in the different error, which is the index error over here, right? Because you're trying to access an element of the array, right? Which is not really valid over here, right? So, an index error will be raised by the Python interpreter,
11:44
right? So, here every except block that you have has been defined for both the exceptions, as one of them receives the exceptions of type index error and the other receives the exception of the type zero error. And the moment you come across an error, that's where you're actually
12:01
going to halt the code and go into the except block. So, you're not going to go and execute the rest of the lines. Now, that was about how you can use a try block, catch, except block, I'm sorry, catch and except, but yeah, you can have multiple except blocks. But what if you also want to consider the scenario where you yourself want to raise some
12:26
errors, right? So, even though exceptions in Python are automatically raised in runtime, when some kind of an error occurs, there are ways to have custom and predefined exceptions also that can be thrown manually as well for raising it for specific conditions, right?
12:44
On a scenario where you use the raise keyword. The idea being that you do not really want to wait for the, you know, interpreter to throw you an error, right? You want to make sure that your code is so strictly and well defined that whenever an error comes up, right, you have
13:00
written those certain keywords and assertions yourself where you know where you want to throw those errors. So, this is kind of an exceptional case. You can optionally pass values also to those exceptions, right, to clarify what kind of and why that kind of exception is being raised. Again, the syntax for that is very simple. You have a try block, again, the
13:23
critical code goes into that and on specific like condition, right, or otherwise as well if you just want to test out the code, you can do raise and then after that you can just write some error over there, right, and you can just mention a message also as in why you are raising that kind of error, right? And in the except block, you are going to raise that particular
13:44
error that it says some error over here and then you can just do some sort of, you know, printing statement on that or maybe how do you want to handle that piece of code. So, here if you will see again we have a syntactical code over here. You have a try block
14:02
which has a variable a which has the values one, two, and three, right, and now you're calling a function is string empty. So, in this piece of code, right, the variable a can hold whatever value that is assigned to it. Here we have assigned it a number, right, and we are passing
14:21
it to a custom method which is is string empty that checks whether the variable pass has a string in it or is it empty or not, okay? So, it could be either a string or it could be a empty string as well. But what we did was we orchestrated the code to be written in such a way that we're actually throwing a type error because we are actually
14:44
assigning a number to a variable, right? So, in this method, we are checking if the variable is a string or not and it holds a value or not. So, in this case, it is supposed to be a string, but it is assigned as a number and that is why we are raising a specific exception type error
15:02
or a value error in this case, right? So, what will happen is whenever you'll try to execute this piece of code, right, you're going to come across the type error exception, right, wherein the type of a in the first if condition the type of a is not equal to string and that is why you are raising a type error where you are saying that a has to be a string,
15:26
okay? So, like we talked about the syntax you do raise you do type error you mention the error that you really want to raise and after that you have the part that you are mentioning a message also because you just don't want to throw the errors, right? That's not what the objective
15:40
is. You want to throw out the errors, but the client should also know the relevant reason why that error is being thrown. So, that's why although sending a message is completely optional, but it's definitely a good practice to do that because when you're on the other end, when you're on the receiving end of errors, it can become difficult on the debugging end
16:01
to understand why that error has been thrown. So, as a general practice, I always recommend to throw a relevant and a readable message to the client, right? Not giving any details which are internal to the server, but also making sure that the user understand all those errors and they can do relevant changes which are required so that it's easier for the client
16:24
to take relevant actions on top of those errors. So, that's what the overall idea is. Next, not just try and accept, but Python as a language gives you a lot more functionalities on top of that as well, which can actually help you to, you know, make your code more robust,
16:43
right? And you can handle multiple scenarios that come along with it. For example, in some situations, you might want to run a block of code, right? If the code inside the try ran without any errors, right? And for those cases, you can use the else keyword also along with
17:04
try keyword, okay? Again, let's take an example. So, again, the try block will have your critical keys of code, right? On some specific condition or otherwise, let's say you want to throw some error and you have sent an optional message as well. Now, in the except case, you're just handling the error. So, remember that the except clause or the except block of
17:26
code only executes when there's an error. If there is no error, the except block will never, ever execute, right? It only executed only gets executed if we have an error. If we get an error in the try block, right? And we're handling the exception in the object that we have as
17:44
E and we're taking relevant actions. Apart from that, in the else block, that else block only gets executed if no exception has been raised, okay? So, only when the code was exception free, like I like to say it, then only you have your else block executed. So, let's see.
18:04
Here we have, again, a piece of code in which you have a try block, you're entering a number taken by the user, and then you're asserting, right? Whether the, I would say, the remainder that you got on division of that number with two is zero or not. Basically, you're trying to
18:21
see whether the number is even or not. So, what will happen is if you will pass an odd number in this code, right? You will go into the except block, okay? And you will simply get the message, not an even number. That will happen when you're passing an odd number. But if you will pass an even number, the except block is not going to be executed because
18:42
the number was indeed even, and you will move to the else block where you will see that the reciprocal of that number will be computed. So, if you enter the number four, you'll get the remainder zero, and you'll simply from the try block, you'll go to the else block. And when you will do one by four, which is for the original number, you'll get 0.25.
19:03
And then you'll just print that output, right? So, if there's a try block, you'll execute. If there's an exception, you'll go to the except clause. And if there is no exception from the try block, you'll go to the else block, right? However, in this code, if you will pass zero, right? Now, there's a scenario, let's say you are passing zero. So, when you do
19:23
zero mod two equal to zero, that's actually a zero division error, right? So, the code, right, will go into the except clause, right? And here, even in the except clause, what will happen over here is you will actually have a trace back over here, right? Trace back basically helps you to understand and trace back on what levels your code basically,
19:44
you know, tried to give you an error and how do you trace back that error, right? So, what will happen is if you basically pass zero over here, you get a zero division error, right? As the code inside else is not handled by the preceding except. So,
20:00
sometimes what happens is a code may be prone to error, right? And here, in this case, when there was a zero division error, you did not handle that in except and you did not handle that in else as well. So, in that case, you'll have a proper error where no error handling has been done. So, now, in the another part that you have along with it is finally as well.
20:24
So, the try statement is Python can also have a finally clause. Now, this clause is executed no matter what and is generally used to, you know, release external resources. Let's take a real example. For example, you're connected to a remote data center through your network
20:40
or working with the file or like, you know, a GUI, a graphical user interface. In all of these circumstances, you must clean up the resources before the program comes to a halt, right? Irrespective of the fact whether your code executed successfully or not, you have to make sure that just because you came across an error, you're not still holding on
21:01
to the resources. Now, these actions closing a file, GUI or disconnecting from the network are performed in the finally clause to guarantee the execution of the code. Now, here is an example for that. You have, let's say, a function where you're reading a file's content, right? And in the try block, you're opening the file, right? You're getting access
21:24
to a JSON and you're reading that JSON, right? But in some case, let's say, while opening it, you come across an error due to some server issues, right? Now, what will happen is, although you are giving a relevant message to the user that you were not able to read the specified file and you are handling the exception or that error well, you also need to make sure that even
21:45
after the exception has been traced, the finally block is being executed, right? Which is closing to the access to that file. Now, remember, people do get confused between the finally block and the else block over here. The else block will not execute if the except block is executed.
22:03
But sure, in this case, the finally block will get executed no matter, I would say, whether you did face an exception or whether you did not face an exception. So, that's very crucial when you're holding onto resources in your code and you might want to let go of them, making sure that you're not holding to the resources irrelevant of your use case.
22:26
And the last one that's very important and that's very important to conclude as well is where you see all of them together finally. That is where you have try, except, else, and finally. So, in this code, you have a try block, you have an array,
22:40
and you're trying to access anything at the index one. If you have an except block, right, you're creating an array over here in the three elements, and that is the maximum index that it goes up is to do. But when you try to access the second index, right, now, it will not raise an exception and control will finally go to another block, right, and then to the finally block, right. But here we need to observe that finally block has been
23:04
triggered even though the exception was not raised. So, if you do temp of one over here, you will execute the else block and then you will execute the finally block. But if you do raise an exception, you will execute the except block and the finally block. So, finally block,
23:21
irrespective of whether you face error or not, an except and I would say else block goes, does not go in hand in hand, right. So, if either you execute the except clause or you execute the else clause, right. So, these all basically in a nutshell form a very important part of how do you really want to hear or like I would say handle the scenarios, right. Using try
23:46
and except is just the way you get started into this journey, right. But what if you want to go one level deeper into it, right. Another scenario that you might consider is that what happens if the errors are basically raised in except or finally block, right. What if you've
24:03
written some piece of code, right, and the error actually comes into the finally block or the except block. Let's say you're doing something to handle the error in the except block and the error happens in the except block itself, right. So, if an error occurs while you're actually handling something in the except block itself, the finally block is still there to save you,
24:25
right. So, you do an error in try block, the except block is there for you. But what if you do error in the except block itself? Then you also have finally block to basically take care for you, right. Now, over here, once an exception or an error is raised in the except block,
24:42
the finally block is triggered, right. But the program still goes into a halt state, post to that and the flow will still get broken. Finally block will help you to raise relevant, I would say, or help you to relevantly show the error to the user. But the program will still go into a halting state. But if an error occurs in the finally block, right, what will happen
25:05
over here is during handling, there also in the finally block, you can raise an exception, right. And it will still show you the finally error. So, the finally block won't be completed beyond this point, right. And the exception is still thrown, right. So, that's what the overall idea
25:23
is. I hope that that was useful for all of you to consider different scenarios. Again, the idea being is that you start small, but as soon as you realize that your complexity of the code is increasing, right. When you're dealing with objects on a very frequent basis, right. You're dealing with a scenario where you're coming across errors very frequently. You're
25:44
coming across a situation where there's a situation, you know, you're trying to place an order, you're building an e-commerce system, you're trying to check out the items in the cart, right. And there's some error, but you still want to show relevant messages to the users so that they can basically get their order ID, right. And whether it's taking
26:03
time to process that order, the customers do have relevant order IDs or, you know, some values or booking reference numbers available during their checkout scenarios, right. They do have that order ID using which they can raise relevant queries, right. Even if your booking was successful or failed, right, or partially failed or some error happened.
26:24
But the checkout experience is smooth so that the people do have a relevant order ID using which they can generate relevant errors. That happens a lot when you're, you know, booking and making reservations online, right. You do make a reservation, but it's taking some time to the partner to confirm your order and to confirm that actually you've received the relevant
26:44
booking as well. So at that time you do still get a reference number and order ID that is created irrespective of your booking that happened successfully or unsuccessfully. So in those situations, it makes a lot of sense to have an Excel block or finally block so that
27:01
it's comfortable for the users as well, the clients as well, the server, the maintainers, and the software engineers as well, as well as the partners who are dealing with it. And that concludes my talk for today as well. I hope you did find it useful and you would be able to incorporate it all as well in the future engineering practice that you do take care of.
27:21
Thank you so much, everyone. Thank you very much, Rhea Banzal for this talk. And with this, we will close the session and let's give her, thanks again for this great talk and see you
27:40
during the next conference. Bye everyone. Thank you so much.