I have some code in a Python except
clause that is intended to do some logging, but the logging code might itself cause an exception. In my case, I'd like to just ignore any second exception that might occur, and raise the original exception. Here is a very simplified example:
try: a = this_variable_doesnt_exist except: try: 1/0 except: pass raise
Running the above code, I hope to get:
NameError: name 'this_variable_doesnt_exist' is not defined
but instead, in Python 2.x, I get:
ZeroDivisionError: integer division or modulo by zero
I've discovered that in Python 3.x, it does what I want.
I couldn't find much commentary on this in the Python 2.x docs (unless I missed it). Can I achieve this in 2.x?
The try and except Block: Handling Exceptions. The try and except block in Python is used to catch and handle exceptions. Python executes code following the try statement as a “normal” part of the program. The code that follows the except statement is the program's response to any exceptions in the preceding try clause ...
If you write the code to handle a single exception, you can have a variable follow the name of the exception in the except statement. If you are trapping multiple exceptions, you can have a variable follow the tuple of the exception.
The try block lets you test a block of code for errors. The except block lets you handle the error. The else block lets you execute code when there is no error. The finally block lets you execute code, regardless of the result of the try- and except blocks.
In Python, exceptions can be handled using a try statement. The critical operation which can raise an exception is placed inside the try clause. The code that handles the exceptions is written in the except clause. We can thus choose what operations to perform once we have caught the exception.
I believe what you're seeing is the result of exception chaining, which is a change in Python 3.
From the Motivation section of the PEP:
During the handling of one exception (exception
A
), it is possible that another exception (exceptionB
) may occur. In today's Python (version 2.4), if this happens, exceptionB
is propagated outward and exceptionA
is lost. In order to debug the problem, it is useful to know about both exceptions. The__context__
attribute retains this information automatically.
The PEP then goes on to describe the new exception chaining (which is implemented in Py3k) in detail—it's an interesting read. I learned something new today.
With abstraction:
def log_it(): try: 1 / 0 except: pass try: this = that except: log_it() raise
Does what you want in Python 2.5
Another way to do it is to store the exception in a variable, then re-raise it explicitly:
try: this = that except NameError, e: # or NameError as e for Python 2.6 try: 1 / 0 except: pass raise e
Note that you probably shouldn't just be using a bare except
to catch everything that might come - it's usually best to catch the specific exceptions you expect to occur in case a drastic and fatal exception (like being out of memory) occurs.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With