David Y.
—How do I raise/throw an exception in Python so that it will be caught by an except
block?
We can use Python’s raise
statement to raise an exception:
raise Exception("Error message here.")
The above is a simple example to demonstrate the syntax, but will be inappropriate for most practical use cases. Below, we discuss some nuances of exceptions and error handling in Python.
Python provides a large number of default exceptions arranged in a class hierarchy from least to most specific. When catching exceptions, all subclasses will be caught by except
clauses using their parents. Therefore, the topmost class Exception
is likely to be missed in favor of an exception that uses one of its subclasses. Consider the code below:
def divide_by_zero(): return 1 / 0 # will fail and raise a ZeroDivisionError try: divide_by_zero() raise Exception("My custom exception.") except Exception as e: print(f"Caught error: {repr(e)}")
Although the try
/except
block may have been written to catch our custom exception, it will instead catch the ZeroDivisionError
raised first, elsewhere in the code. While this does not present an obvious problem in our example code, as we print the exception’s error message regardless, this may not be the case for larger projects, where we might choose to do something other than printing the error message in the except
block. In a sufficiently complex codebase, this over-broad exception catching could make debugging very difficult.
Therefore, we should always raise the most specific exceptions possible and avoid placing a large amount of code in try
blocks, unless this code contains its own error handling.
Where necessary, we can also make use of multiple except
blocks, as below:
def divide_by_zero(): return 1/0 # will fail and raise a ZeroDivisionError try: divide_by_zero() raise Exception("My custom exception.") except ValueError as e: print(f"Caught value error: {repr(e)}") except Exception as e: print(f"Caught custom exception: {repr(e)}")
Note that the except
blocks above are ordered from most to least specific. This will ensure that all exceptions are caught by the most appropriate handler.
In addition to the error message provided in the first parameter, the Exception
constructor can be given any number of additional values as arguments. It will store these in a tuple called args
.
try: raise Exception("My custom exception.", 1, "a", True) except Exception as e: print(e.args) # will print (1, "a", True)
These values may be useful for retrieving specific details about the error that occurred, allowing us to construct complex error-handling logic.
If none of the built-in exceptions is appropriate, we can create our own exceptions by subclassing Exception
or any of its subclasses. For example:
class MyValueError(ValueError): """ Raise when a custom value error occurs.""" def divide_by_zero(): return 1/0 # will fail and raise a ZeroDivisionError try: raise MyValueError("My custom exception.") divide_by_zero() except MyValueError as e: print(f"Caught custom value error: {repr(e)}") except ValueError as e: print(f"Caught built-in value error: {repr(e)}")
This code will catch the first error in the first except
block. If we remove the line beginning with raise MyValueError
, then it will catch the ZeroDivisionError
produced by the divide_by_zero()
function.
Python 3 introduced the from
clause to raise
, which is used for chaining exceptions. This can be useful for debugging.
def divide_by_zero(): return 1 / 0 # will fail and raise a ZeroDivisionError try: divide_by_zero() except Exception as e: raise RuntimeError("Critical failure.") from e
This will produce the following output, showing tracebacks from all chained exceptions:
Traceback (most recent call last): File "/tmp/main.py", line 5, in <module> divide_by_zero() File "/tmp/main.py", line 2, in divide_by_zero return 1/0 # will fail and raise a ZeroDivisionError ~^~ ZeroDivisionError: division by zero The above exception was the direct cause of the following exception: Traceback (most recent call last): File "/tmp/main.py", line 7, in <module> raise RuntimeError("Critical failure.") from e RuntimeError: Critical failure. shell returned 1
Tasty treats for web developers brought to you by Sentry. Get tips and tricks from Wes Bos and Scott Tolinski.
SEE EPISODESConsidered “not bad” by 4 million developers and more than 100,000 organizations worldwide, Sentry provides code-level observability to many of the world’s best-known companies like Disney, Peloton, Cloudflare, Eventbrite, Slack, Supercell, and Rockstar Games. Each month we process billions of exceptions from the most popular products on the internet.
Here’s a quick look at how Sentry handles your personal information (PII).
×We collect PII about people browsing our website, users of the Sentry service, prospective customers, and people who otherwise interact with us.
What if my PII is included in data sent to Sentry by a Sentry customer (e.g., someone using Sentry to monitor their app)? In this case you have to contact the Sentry customer (e.g., the maker of the app). We do not control the data that is sent to us through the Sentry service for the purposes of application monitoring.
Am I included?We may disclose your PII to the following type of recipients:
You may have the following rights related to your PII:
If you have any questions or concerns about your privacy at Sentry, please email us at compliance@sentry.io.
If you are a California resident, see our Supplemental notice.