- Introduction to Python Exceptions
- Python Exceptions Handling: try except Statements
- Raising Python Exceptions Manually
- Python Exceptions Practice Problems
Introduction to Python Exceptions
In our Getting Started with Python guide, we briefly introduced the concept of Python exceptions as being Python’s answer to runtime errors1. In this tutorial, we’ll focus more on how Python processes those exceptions, how to make your own exceptions, and how to handle Python exceptions to prevent your entire program from crashing.
What are Python Exceptions?
In Python, an exception is an error that we can manage, or handle. In earlier tutorials, we talked about a few different exceptions, like the following:
100/0 # Divide by zero > ZeroDivisionError: division by zero print(UndefinedVariable) > NameError: name 'UndefinedVariable' is not defined
Exceptions are raised when Python encounters an action it cannot perform. After each of these exceptions were raised, the entire program aborted; the program ended whether it was running for 4 seconds or 4 days. This means that if we don’t want to ruin all of the work the program has performed, we’ll have to properly manage these exceptions.
Each of these Python exceptions can be avoided with careful planning and logic to avoid any illegal operation, however exceptions in Python can be handled in more relaxed ways. As we mentioned in the Getting Started with Python guide, Python has built in the philosophy of “better to ask for forgiveness than for permission” in the form of Python exceptions handling.
All the exceptions raised by Python are subclasses of the superclass
Python Exceptions Handling: try except Statements
Now that we understand the consequences of exceptions, let’s look at how we can handle them gracefully using Python’s native exceptions handling tools. The primary tool for exceptions handling with Python is the
try except context manager. This context manager has the following fundamental form:
try: [statement] except: [FailureStatement]
if statements and
for loops, everything defined within the
except indentations (tab or 4 spaces) will be included when those statements are executed.
Let’s look at each section in detail.
try statement invokes the context manager, and everything within the
try block (
try statement is reached. If any exception is raised within the
try block, then the code within the
except block (
try block, then the context manager is exited and the
except code block is skipped. You’ll only enter the
except block of a Python exception, or error, is raised.
a, b = 4, 2 # This will succeed out = None try: out = a/b except: out = "Can't divide by 0!" print(out) > 2.0
In the above example, the
try statement code block was executed without raising any exception, therefore the
except code block was skipped and the variable
out has printed to the terminal as the correct quotient. Now let’s try a division that will fail:
a, b = 4, 0 # This will fail out = None try: out = a/b except: out = "Can't divide by 0!" print(out) > Can't divide by 0!
try code block raised an exception, and the
except code block was executed. The most important thing to notice in this example is that even though a
ZeroDivisionError was raised the program did not abort since it was tested within the
try context manager. This is extremely helpful for cases in which we know an error could occur in our program, and want to deal with the problem gracefully rather than have the program crash.
Enter your email address for more free Python tutorials and tips.
Proper Form: Narrowing try except Scope
In the previous section, we used the general form of a
try except statement that executed the
except code block whenever any exception was raised. Suppose we instead executed the following:
a = 4 out = None try: out = a/c # c was never defined except: out = "Can't divide by 0!" print(out) > 'Can't divide by 0!
In this case, we handled the exception in the case that the divisor was 0, however in this case the actual error that was raised was the
NameError arising from the undefined
c variable. Rather than allow the program to continue with the false assumption that it only raised a
ZeroDivisionError exception, we may want the program to abort so we can properly debug the code.
This situation is why it is considered good form to narrow the scope of the exceptions that are handled by the
try except statements. We narrow the scope by simply extending the format as follows:
try: [statement] except [Exception]: [FailureStatement]
Here we can define a tuple of valid exceptions within the
except statement. All other exceptions will abort the program unless they are handled within an outer-nested
Let’s look at narrowing down some of our previous examples:
a, b = 4, 0 out = None try: out = a/b except ZeroDivisionError: out = "Can't divide by 0!" print(out) > 'Can't divide by 0!' a = 4 out = None try: out = a/c # c was never defined except ZeroDivisionError: out = "Can't divide by 0!" print(out) > NameError: name 'c' is not defined
If we expect several different exceptions to arise within the
try statement code block, then we can add additional
a, b = 4, 0 out = None try: out = a/b except ZeroDivisionError: out = "Can't divide by 0!" except NameError: # Second except to check for NameError out = "Can't find a variable!" print(out) > 'Can't divide by 0!' out = None try: out = a/c except ZeroDivisionError: out = "Can't divide by 0!" except NameError: out = "Can't find a variable!" print(out) > 'Can't find a variable!'
Extending to try except else finally Statements
In the above examples, we used the short form of the
try except statement, however we can extend the full statement to the following for more robust Python exceptions handling and control:
try: [statement] except [Exception]: [FailureStatement] else: [ElseStatement] finally: [FinalStatement]
else statement block will only be executed if no exception is raised in the
try code block, and the
finally statement block will execute whether an exception is raised or not. The
finally statement can be especially useful during the execution of time-intensive code to perform clean-up actions in the event that the user stops the code execution with a keyboard interrupt.
Raising Python Exceptions Manually
When writing code, we may determine that there are some situations in which we will want to raise an exception manually. For example, suppose we wish to define a function
dabs(x) that is the derivative of the absolute value function
abs(x). The derivative of the absolute value function is undefined at 0, therefore we would want to ensure that any input
dabs(0) will cause an error. We can raise an error ourselves using the
raise [Exception]([ErrText]) statement format, which will raise the given
We define the
dabs(x) function as follows:
def dabs(x): if x > 0: return 1 elif x < 0: return -1 else: # x = 0 raise ValueError("Derivative undefined at 0") dabs(20) > 1 dabs(0) > ValueError: Derivative undefined at 0
Note that in the above raise statement, we used an already existing builtin exception
ValueError, which is why we didn’t have to define that keyword.
Creating New Exceptions
If the builtin Python exceptions are not adequate for the use of raising exceptions, we can create our own exceptions using classes. When we create these custom classes, we will inherit the standard exception attributes from the superclass
Exception. Because all the necessary methods and attributes are inherited from
Exception, we only have to include a
pass statement within the body of the class.
pass statement is fairly boring: it does absolutely nothing. When Python processes the
pass statement, it will simply continue executing the code as though it were not there. The usefulness of the
pass statement is in cases where Python expects some form of input, such as within defined functions and classes.
For example, we can define a new
dabs(x) function like this:
class UndefinedDerivative(Exception): pass def dabs(x): if x > 0: return 1 elif x < 0: return -1 else: # x = 0 raise UndefinedDerivative("Derivative undefined at 0") dabs(0) > UndefinedDerivative: Derivative undefined at 0
You see how the name of the exception is now
To help you get more comfortable with Python exceptions and how to handle them, let’s take a look at a few practice problems. Before we do that, though, did you find this free tutorial helpful? Subscribe below and share this article with your friends, classmates, and coworkers on Facebook and Twitter! When you spread the word on social media, you’re helping us grow so we can continue to provide free tutorials like this one for years to come.
Enter your email address for more free Python tutorials and tips.
Python Exceptions Practice Problems
openfunction cannot find a given file, it will raise a
FileNotFoundErrorexception. Write a
try exceptstatement that will handle such an exception. Solution
Suppose you have the following list of numbers:
l = [[0,1], [2,3], [3,5], [5,8],]
Write a Python code to divide each pair of numbers with the second number divided by the first (i.e.
l/l) and save the results in a list
ZeroDivisionError exception occurs, then save the result as the float
3. Write a program that allows a user to input two numbers, and print the result of the division of those numbers. If a
ZeroDivisionError exception occurs, alert the user and ask for two numbers again.
4. Write a program that allows a user to input one number. If the number is greater than 255, raise a
ValueError with an informative message.
5. Repeat problem 4, but instead of raising a
ValueError exception, write and raise a custom exception called
file = "NotHere" try: with open(file, "r") as f: pass #I/O Operations here except FileNotFoundError: message = "File " + file + " was not found." print(message) > File NotHere was not found.
l = [[0,1], [2,3], [3,5], [5,8],] golden =  for i in l: try: golden.append(i/i) except ZeroDivisionError: golden.append(float("nan")) print(golden) > [nan, 1.5, 1.666667, 1.6]
while True: print("This program will return a/b") a = float(input("Enter a: ")) b = float(input("Enter b: ")) try: r = a/b except ZeroDivisionError: print("Sorry, cannot divide by 0. Try again.") else: print(r) break
a = float(input("Enter a number: ")) if a > 255: raise ValueError("Number greater than 255")
class OutsideThresholdError(Exception): pass a = float(input("Enter a number: ")) if a > 255: raise OutsideThresholdError("Number greater than 255")
There also exists syntax errors that occur during interpretation of a section of code. These errors are typically not included under the umbrella of exceptions, and cannot be handled in the same manner. Syntax errors arise from improper coding, thus the correct way of handling them is to fix the code. ↩