Errors and Exceptions
No matter your skill as a programmer, you will eventually make a coding mistake. Such mistakes come in three basic flavors:
Syntax errors: Errors where the code is not valid Python (generally easy to fix)
Runtime errors: Errors where syntactically valid code fails to execute, perhaps due to invalid user input (sometimes easy to fix)
Semantic errors: Errors in logic: code executes without a problem, but the result is not what you expect (often very difficult to track-down and fix)
Here we're going to focus on how to deal cleanly with runtime errors. As we'll see, Python handles runtime errors via its exception handling framework.
Runtime Errors
If you've done any coding in Python, you've likely come across runtime errors. They can happen in a lot of ways.
For example, if you try to reference an undefined variable:
Or if you try an operation that's not defined:
Catching Exceptions: try
and except
try
and except
The main tool Python gives you for handling runtime exceptions is the try
...except
clause. Its basic structure is this:
Note that the second block here did not get executed: this is because the first block did not return an error. Let's put a problematic statement in the try
block and see what happens:
Here we see that when the error was raised in the try
statement (in this case, a ZeroDivisionError
), the error was caught, and the except
statement was executed.
One way this is often used is to check user input within a function or another piece of code. For example, we might wish to have a function that catches zero-division and returns some other value, perhaps a suitably large number like 10^100:
There is a subtle problem with this code, though: what happens when another type of exception comes up? For example, this is probably not what we intended:
Dividing an integer and a string raises a TypeError
, which our over-zealous code caught and assumed was a ZeroDivisionError
! For this reason, it's nearly always a better idea to catch exceptions explicitly:
Raising Exceptions: raise
raise
We've seen how valuable it is to have informative exceptions when using parts of the Python language. It's equally valuable to make use of informative exceptions within the code you write, so that users of your code (foremost yourself!) can figure out what caused their errors.
The way you raise your own exceptions is with the raise
statement. For example:
As an example of where this might be useful, let's return to our fibonacci
function that we defined previously:
One potential problem here is that the input value could be negative. This will not currently cause any error in our function, but we might want to let the user know that a negative N
is not supported. Errors stemming from invalid parameter values, by convention, lead to a ValueError
being raised:
Now the user knows exactly why the input is invalid, and could even use a try
...except
block to handle it!
Diving Deeper into Exceptions
Briefly, I want to mention here some other concepts you might run into. I'll not go into detail on these concepts and how and why to use them, but instead simply show you the syntax so you can explore more on your own.
Accessing the error message
Sometimes in a try
...except
statement, you would like to be able to work with the error message itself. This can be done with the as
keyword:
With this pattern, you can further customize the exception handling of your function.
Defining custom exceptions
In addition to built-in exceptions, it is possible to define custom exceptions through class inheritance. For instance, if you want a special kind of ValueError
, you can do this:
You might find this useful as you develop more customized code.
try
...except
...else
...finally
try
...except
...else
...finally
In addition to try
and except
, you can use the else
and finally
keywords to further tune your code's handling of exceptions. The basic structure is this:
The utility of else
here is clear, but what's the point of finally
? Well, the finally
clause really is executed no matter what: I usually see it used to do some sort of cleanup after an operation completes.
Last updated