Recommended Video Course
Raising and Handling Python Exceptions
Table of Contents
Watch Now This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding:Raising and Handling Python Exceptions
Python exceptions provide a mechanism for handling errors that occur during the execution of a program. Unlike syntax errors, which are detected by the parser, Python raises exceptions when an error occurs in syntactically correct code. Knowing how to raise, catch, and handle exceptions effectively helps to ensure your program behaves as expected, even when encountering errors.
By the end of this tutorial, you’ll understand that:
try
…except
block lets you execute code and handle exceptions that arise.else
, andfinally
keywords for more refinedexception handling.except Exception
or the bareexcept
clause.try
,except
, andpass
allows your program tocontinue silently without handling the exception.In this tutorial, you’ll get to know Python exceptions and all relevant keywords for exception handling by walking through a practical example of handling a platform-related exception. Finally, you’ll also learn how to create your own custom Python exceptions.
Get Your Code:Click here to download the free sample code that shows you how exceptions work in Python.
Take the Quiz: Test your knowledge with our interactive “Python Exceptions: An Introduction” quiz. You’ll receive a score upon completion to help you track your learning progress:
Interactive Quiz
Python Exceptions: An IntroductionIn this quiz, you'll test your understanding of Python exceptions. You'll cover the difference between syntax errors and exceptions and learn how to raise exceptions, make assertions, and use the try and except block.
Syntax errors occur when the parser detects an incorrect statement. Observe the following example:
>>> print(0 / 0)) File"<stdin>", line1print(0/0))^SyntaxError:unmatched ')'
The arrow indicates where the parser ran into thesyntax error. Additionally, the error message gives you a hint about what went wrong. In this example, there was one bracket too many. Remove it and run your code again:
>>>print(0/0)Traceback (most recent call last): File"<stdin>", line1, in<module>ZeroDivisionError:division by zero
This time, you ran into anexception error. This type of error occurs whenever syntactically correct Python code results in an error. The last line of the message indicates what type of exception error you ran into.
Instead of just writingexception error, Python details whattype of exception error it encountered. In this case, it was aZeroDivisionError
. Python comes withvarious built-in exceptions as well as the possibility to create user-defined exceptions.
There are scenarios where you might want to stop your program by raising an exception if a condition occurs. You can do this with theraise
keyword:
You can even complement the statement with a custom message. Assume that you’re writing a tiny toy program that expects only numbers up to5
. You can raise an error when an unwanted condition occurs:
low.py
number=10ifnumber>5:raiseException(f"The number should not exceed 5. ({number=})")print(number)
In this example, you raised anException
object and passed it an informative custom message. You built the message using anf-string and aself-documenting expression.
When you runlow.py
, you’ll get the following output:
Traceback (most recent call last): File"./low.py", line3, in<module>raiseException(f"The number should not exceed 5. ({number=})")Exception:The number should not exceed 5. (number=10)
The program comes to a halt and displays the exception to yourterminal orREPL, offering you helpful clues about what went wrong. Note that the final call toprint()
never executed, because Python raised the exception before it got to that line of code.
With theraise
keyword, you can raise any exception object in Python and stop your program when an unwanted condition occurs.
assert
Before moving on to the most common way of working with exceptions in Python usingthetry
…except
block, you’ll take a quick look at an exception that’s a bit different than the others.
Python offers a specific exception type that you should only use when debugging your program during development. This exception is theAssertionError
. TheAssertionError
is special because you shouldn’t ever raise it yourself usingraise
.
Instead, you usetheassert
keyword to check whether a condition is met and let Python raise theAssertionError
if the condition isn’t met.
The idea of an assertion is that your program should only attempt to run if certain conditions are in place. If Python checks your assertion and finds that the condition isTrue
, then that is excellent! The program can continue. If the condition turns out to beFalse
, then your program raises anAssertionError
exception and stops right away:
Revisit your tiny script,low.py
, fromthe previous section. Currently, you’re explicitly raising an exception when a certain condition isn’t met:
low.py
number=1ifnumber>5:raiseException(f"The number should not exceed 5. ({number=})")print(number)
Assuming that you’ll handle this constraint safely for your production system, you could replace thisconditional statement with an assertion for a quick way to retain this sanity check during development:
low.py
number=1assert(number<5),f"The number should not exceed 5. ({number=})"print(number)
If thenumber
in your program is below5
, then the assertion passes and your script continues with the next line of code. However, if you setnumber
to a value higher than5
—for example,10
—then the outcome of the assertion will beFalse
:
low.py
number=10assert(number<5),f"The number should not exceed 5. ({number=})"print(number)
In that case, Python raises anAssertionError
that includes the message you passed, and ends the program execution:
$pythonlow.pyTraceback (most recent call last): File "./low.py", line 2, in <module> assert (number < 5), f"The number should not exceed 5. ({number=})" ^^^^^^^^^^AssertionError: The number should not exceed 5. (number=10)
In this example, raising anAssertionError
exception is the last thing that the program will do. The program will then come to halt and won’t continue. The call toprint()
that follows the assertion won’t execute.
Using assertions in this way can be helpful when you’re debugging your program during development because it can be quite a fast and straightforward to add assertions into your code.
However, you shouldn’t rely on assertions for catching crucial run conditions of your program in production. That’s because Python globally disables assertions when you run it in optimized mode using the-O
and-OO
command line options:
$python-Olow.py10
In this run of your program, you used the-O
command line option, which removes allassert
statements. Therefore, your script ran all the way to the end and displayed a number that isdreadfully high!
Note: Alternatively, you can also disable assertions through thePYTHONOPTIMIZE
environment variable.
In production, your Python code may run using this optimized mode, which means that assertions aren’t a reliable way to handle runtime errors in production code. They can be quick and useful helpers when your debugging your code, but you should never use assertions to set crucial constraints for your program.
Iflow.py
should reliably fail whennumber
is above5
, then it’s best to stick withraising an exception. However, sometimes you might not want your program to fail when it encounters an exception, so how should you handle those situations?
try
andexcept
BlockIn Python, you use thetry
andexcept
block to catch and handle exceptions. Python executes code following thetry
statement as a normal part of the program. The code that follows theexcept
statement is the program’s response to any exceptions in the precedingtry
clause:
As you saw earlier, when syntactically correct code runs into an error, Python will raise an exception error. This exception error will crash the program if you don’t handle it. In theexcept
clause, you can determine how your program should respond to exceptions.
The following function can help you understand thetry
andexcept
block:
linux_interaction.py
deflinux_interaction():importsysif"linux"notinsys.platform:raiseRuntimeError("Function can only run on Linux systems.")print("Doing Linux things.")
Thelinux_interaction()
can only run on a Linux system. Python will raise aRuntimeError
exception if you call it on an operating system other then Linux.
Note: Picking the right exception type can sometimes be tricky. Python comes withmany built-in exceptions that arehierarchically related, so if you browse the documentation, you’re likely to find a fitting one.
Python even groups some of the exceptions into categories, such aswarnings that you should use to indicate warning conditions, andOS exceptions that Python raises depending on system error codes.
If you still didn’t find a fitting exception, then you cancreate a custom exception.
You can give the function atry
by adding the following code:
linux_interaction.py
# ...try:linux_interaction()except:pass
The way you handled the error here is by handing out apass
. If you run this code on a macOS or Windows machine, then you get the following output:
$pythonlinux_interaction.py
You got nothing in response. The good thing here is that your program didn’t crash. But letting an exception that occurred pass silently is bad practice. You should always at least know about andlog if some type of exception occurred when you ran your code.
To this end, you can changepass
into something that generates an informative message:
linux_interaction.py
# ...try:linux_interaction()except:print("Linux function wasn't executed.")
When you now execute this code on a macOS or Windows machine, you’ll see the message from yourexcept
block printed to the console:
$pythonlinux_interaction.pyLinux function wasn't executed.
When an exception occurs in a program that runs this function, then the program will continue as well as inform you about the fact that the function call wasn’t successful.
What you didn’t get to see was the type of error that Python raised as a result of the function call. In order to see exactly what went wrong, you’d need to catch the error that the function raised.
The following code is an example where you capture theRuntimeError
and output that message to your screen:
linux_interaction.py
# ...try:linux_interaction()exceptRuntimeErroraserror:print(error)print("The linux_interaction() function wasn't executed.")
In theexcept
clause, you assign theRuntimeError
to the temporary variableerror
—often also callederr
—so that you can access the exception object in the indented block. In this case, you’re printing the object’s string representation, which corresponds to the error message attached to the object.
Running this function on a macOS or Windows machine outputs the following:
$pythonlinux_interaction.pyFunction can only run on Linux systems.The linux_interaction() function wasn't executed.
The first message is theRuntimeError
, informing you that Python can only execute the function on a Linux machine. The second message tells you which function wasn’t executed.
In the example above, you called a function that you wrote yourself. When you executed the function, you caught theRuntimeError
exception and printed it to your screen.
Here’s another example where you open a file and use a built-in exception:
open_file.py
try:withopen("file.log")asfile:read_data=file.read()except:print("Couldn't open file.log")
Iffile.log
doesn’t exist, then this block of code will output the following:
$pythonopen_file.pyCouldn't open file.log
This is an informative message, and your program will still continue to run. However, yourexcept
block will currently catchany exception, whether that’s related to not being able to open the file or not. You could lead yourself onto a confusing path if you see this message even when Python raises a completely unrelated exception.
Therefore, it’s always best to bespecific when you’re handling an exception.
In thePython docs, you can see that there are a couple of built-in exceptions that you could raise in such a situation, for example:
exception
FileNotFoundError
Raised when a file or directory is requested but doesn’t exist. Corresponds to errno ENOENT. (Source)
You want to handle the situation when Python can’t find the requested file. To catch this type of exception and print it to screen, you could use the following code:
open_file.py
try:withopen("file.log")asfile:read_data=file.read()exceptFileNotFoundErrorasfnf_error:print(fnf_error)
In this case, iffile.log
doesn’t exist, then the output will be the following:
$pythonopen_file.py[Errno 2] No such file or directory: 'file.log'
You can have more than one function call in yourtry
clause and anticipate catching various exceptions. Something to note here is that the code in thetry
clause will stop as soon as it encounters any one exception.
Warning: When you use a bareexcept
clause, then Python catches any exception that inherits fromException
—which are most built-in exceptions! Catching the parent class,Exception
, hides all errors—even those which you didn’t expect at all. This is why you should avoid bareexcept
clauses in your Python programs.
Instead, you’ll want to refer tospecific exception classes that you want to catch and handle. You can learn more about why this is a good ideain this tutorial.
Look at the following code. Here, you first calllinux_interaction()
and then try to open a file:
linux_interaction.py
# ...try:linux_interaction()withopen("file.log")asfile:read_data=file.read()exceptFileNotFoundErrorasfnf_error:print(fnf_error)exceptRuntimeErroraserror:print(error)print("Linux linux_interaction() function wasn't executed.")
If you run this code on a macOS or Windows machine, then you’ll see the following:
$pythonlinux_interaction.pyFunction can only run on Linux systems.Linux linux_interaction() function wasn't executed
Inside thetry
clause, you ran into an exception immediately and didn’t get to the part where you attempt to openfile.log
. Now look at what happens when you run the code on a Linux machine if the file doesn’t exist:
$pythonlinux_interaction.py[Errno 2] No such file or directory: 'file.log'
Note that if you’re handling specific exceptions as you did above, then the order of theexcept
clauses doesn’t matter too much. It’s all about which of the exceptions Python raises first. As soon as Python raises an exception, it checks the except clauses from top to bottom and executes the first matching one that it finds.
Here are the key takeaways about using Python’stry
…except
statements:
try
clause up until the point where it encounters the first exception.except
clause—the exception handler—you determine how the program responds to the exception.except
clauses, because they can hide unexpected exceptions.While usingtry
together withexcept
is probably the most common error handling that you’ll encounter, there’s more that you can do to fine-tune your program’s response to exceptions.
else
You can use Python’selse
statement to instruct a program to execute a certain block of code only in the absence of exceptions:
Look at the following example:
linux_interaction.py
# ...try:linux_interaction()exceptRuntimeErroraserror:print(error)else:print("Doing even more Linux things.")
If you were to run this code on a Linux system, then the output would be the following:
$pythonlinux_interaction.pyDoing Linux things.Doing even more Linux things.
Because the program didn’t run intoany exceptions, Python executed the code in theelse
clause. However, if you run this code on a macOS or Windows system, then you get a different output:
$pythonlinux_interaction.pyFunction can only run on Linux systems.
Thelinux_interaction()
function raised aRuntimeError
. You’ve handled the exception, so your program doesn’t crash, and instead prints the exception message to the console. The code nested under theelse
clause, however, doesn’t execute, because Python encountered an exception during execution.
Note that structuring your code like this is different from just adding the call toprint()
outside of the context of thetry
…except
block:
linux_interaction.py
# ...try:linux_interaction()exceptRuntimeErroraserror:print(error)print("Doing even more Linux things.")
If you don’t nest theprint()
call under theelse
clause, then it’ll execute even if Python encounters theRuntimeError
that you handle in theexcept
block above. On a Linux system, the output would be the same, but on macOS or Windows, you’d get the following output:
$pythonlinux_interaction.pyFunction can only run on Linux systems.Doing even more Linux things.
Nesting code under theelse
clause assures that it’ll only run when Python doesn’t encounter any exception when executing thetry
…except
block.
You can also create a nestedtry
…except
block inside theelse
clause and catch possible exceptions there as well:
linux_interaction.py
# ...try:linux_interaction()exceptRuntimeErroraserror:print(error)else:try:withopen("file.log")asfile:read_data=file.read()exceptFileNotFoundErrorasfnf_error:print(fnf_error)
If you were to execute this code on a Linux machine, then you’d get the following result:
$pythonlinux_interaction.pyDoing Linux things.[Errno 2] No such file or directory: 'file.log'
From the output, you can see thatlinux_interaction()
ran. Because Python encountered no exceptions, it attempted to openfile.log
. That file didn’t exist, but instead of letting the program crash, you caught theFileNotFoundError
exception and printed a message to the console.
finally
Imagine that you always had to implement some sort of action to clean up after executing your code. Python enables you to do so using thefinally
clause:
Have a look at the following example:
linux_interaction.py
# ...try:linux_interaction()exceptRuntimeErroraserror:print(error)else:try:withopen("file.log")asfile:read_data=file.read()exceptFileNotFoundErrorasfnf_error:print(fnf_error)finally:print("Cleaning up, irrespective of any exceptions.")
In this code, Python will execute everything in thefinally
clause. It doesn’t matter if you encounter an exception somewhere in any of thetry
…except
blocks. Running the code on a macOS or Windows machine will output the following:
$pythonlinux_interaction.pyFunction can only run on Linux systems.Cleaning up, irrespective of any exceptions.
Note that the code inside thefinally
block will execute regardless of whether or not you’re handling the exceptions:
linux_interaction.py
# ...try:linux_interaction()finally:print("Cleaning up, irrespective of any exceptions.")
You simplified the example code from above, butlinux_interaction()
still raises an exception on a macOS or Windows system. If you now run this code on an operating system other than Linux, then you’ll get the following output:
$pythonlinux_interaction.pyCleaning up, irrespective of any exceptions.Traceback (most recent call last): ...RuntimeError: Function can only run on Linux systems.
Despite the fact that Python raised theRuntimeError
, the code in thefinally
clause still executed and printed the message to your console.
This can be helpful because even code outside of atry
…except
block won’t necessarily execute if your script encounters an unhandled exception. In that case, your program will terminate and the codeafter thetry
…except
block will never run. However, Python will still execute the code inside of thefinally
clause. This helps you make sure that resources likefile handles anddatabase connections are cleaned up properly.
With the large number of built-in exceptions that Python offers, you’ll likely find a fitting type when deciding which exception to raise. However, sometimes your code won’t fit the mold.
Python makes it straightforward to create custom exception types by inheriting from a built-in exception. Think back to yourlinux_interaction()
function:
linux_interaction.py
deflinux_interaction():importsysif"linux"notinsys.platform:raiseRuntimeError("Function can only run on Linux systems.")print("Doing Linux things.")# ...
Using aRuntimeError
isn’t a bad choice in this situation, but it would be nice if your exception name was a bit more specific. For this, you can create a custom exception:
linux_interaction.py
classPlatformException(Exception):"""Incompatible platform."""# ...
You generally create a custom exception in Python by inheriting fromException
, which is the base class for most built-in Python exceptions as well. You could also inherit from a different exception, but choosingException
is usually the best choice.
That’s really all that you need to do. In the code snippet above, you also added adocstring that describes the exception type and serves as the class body.
Note: Python requires some indented code in the body of your class. Alternatively to using the docstring, you could’ve also usedpass
orthe ellipsis (...
). However, adding a descriptive docstring adds the most value to your custom exception.
While you can customize your exception object, you don’t need to do that. It’s often enough to give your custom Python exceptions a descriptive name, so you’ll know what happened when Python raises this exception in your code.
Now that you’ve defined the custom exception, you can raise it like any other Python exception:
linux_interaction.py
classPlatformException(Exception):"""Incompatible platform."""deflinux_interaction():importsysif"linux"notinsys.platform:raisePlatformException("Function can only run on Linux systems.")print("Doing Linux things.")# ...
If you now calllinux_interaction()
on macOS or Windows, then you’ll see that Python raises your custom exception:
$pythonlinux_interaction.pyTraceback (most recent call last): ...PlatformException: Function can only run on Linux systems.
You could even use your customPlatformException
as a parent class for other custom exceptions that you could descriptively name for each of the platforms that users may run your code on.
At this point, you’re familiar with the basics of using Python exceptions. After seeing the difference between syntax errors and exceptions, you learned about various ways to raise, catch, and handle exceptions in Python. You also learned how you can create your own custom exceptions.
In this article, you gained experience working with the following exception-related keywords:
raise
allows you to raise an exception at any time.assert
enables you to verify if a certain condition is met and raises an exception if it isn’t.try
clause, all statements are executed until an exception is encountered.except
allows you to catch and handle the exception or exceptions that Python encountered in thetry
clause.else
lets you code sections that should run only when Python encounters no exceptions in thetry
clause.finally
enables you to execute sections of code that should always run, whether or not Python encountered any exceptions.Get Your Code:Click here to download the free sample code that shows you how exceptions work in Python.
You now understand the basic tools that Python offers for dealing with exceptions. If you’re curious about the topic and want to dive deeper, then take a look at the following tutorials:
except*
raise
: Effectively Raising Exceptions in Your CodeWhat’s your favorite aspect of exception handling in Python? Share your thoughts in the comments below.
Now that you have some experience with Python exceptions, you can use the questions and answers below to check your understanding and recap what you’ve learned.
These FAQs are related to the most important concepts you’ve covered in this tutorial. Click theShow/Hide toggle beside each question to reveal the answer.
Exceptions in Python are errors that occur during the execution of a program, disrupting the normal flow of the program.
You handle exceptions in Python using atry
…except
block. Python executes the code in thetry
block and if an exception occurs, it switches to executing the code in theexcept
block to handle the exception. However, only the exceptions that are explicitly specified in theexcept
block will be handled. If an exception is not caught, it’ll propagate up the call stack and may result in the termination of your program.
To catch all exceptions in Python, you can use a bareexcept
clause or writeexcept Exception
, but it’s recommended to catch specific exceptions to avoid masking unexpected errors.
In atry
…except
block, Python executes the code undertry
and if an exception occurs, it immediately jumps to theexcept
block to handle it, allowing the program to continue running.
Usingtry
…except
withpass
allows the program to ignore the exception and continue execution without taking any specific action in response to the error. However, this practice can hide potential issues, making it harder to debug and maintain the code, so use it with caution. It’s generally better to either handle the exception explicitly or log it for debugging purposes.
You raise an exception in Python using theraise
keyword followed by an exception object, which can include a custom message.
You can use theassert
keyword to check if a condition is true during development. If the condition is false, it raises anAssertionError
, which can help with debugging. Note that assertions can be disabled by running Python with the-O
(optimize) flag. Therefore, you shouldn’t rely on assertions for critical checks in production code, as they may be ignored.
Thefinally
clause contains code that will always execute after atry
block, regardless of whether an exception was raised or not, ensuring necessary cleanup actions occur.
Take the Quiz: Test your knowledge with our interactive “Python Exceptions: An Introduction” quiz. You’ll receive a score upon completion to help you track your learning progress:
Interactive Quiz
Python Exceptions: An IntroductionIn this quiz, you'll test your understanding of Python exceptions. You'll cover the difference between syntax errors and exceptions and learn how to raise exceptions, make assertions, and use the try and except block.
Watch Now This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding:Raising and Handling Python Exceptions
🐍 Python Tricks 💌
Get a short & sweetPython Trick delivered to your inbox every couple of days. No spam ever. Unsubscribe any time. Curated by the Real Python team.
AboutSaid van de Klundert
Said is a network engineer, Python enthusiast, and a guest author at Real Python.
» More about SaidMasterReal-World Python Skills With Unlimited Access to Real Python
Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:
MasterReal-World Python Skills
With Unlimited Access to Real Python
Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:
What Do You Think?
What’s your #1 takeaway or favorite thing you learned? How are you going to put your newfound skills to use? Leave a comment below and let us know.
Commenting Tips: The most useful comments are those written with the goal of learning from or helping out other students.Get tips for asking good questions andget answers to common questions in our support portal.
Keep Learning
Recommended Video Course:Raising and Handling Python Exceptions
Related Tutorials:
Already have an account?Sign-In
Almost there! Complete this form and click the button below to gain instant access:
Python Exceptions: An Introduction (Sample Code)