31

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?

Craig McQueen
  • 41,871
  • 30
  • 130
  • 181

3 Answers3

24

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 (exception B) may occur. In today's Python (version 2.4), if this happens, exception B is propagated outward and exception A 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.

Alok Singhal
  • 93,253
  • 21
  • 125
  • 158
21

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.

Chris Lutz
  • 73,191
  • 16
  • 130
  • 183
-1

In my CausedException class I take care of that for Python 2.x (and for Python 3 as well, in case you want to pass cause trees instead of simple cause chains). Maybe it can help you.

Duncan Jones
  • 67,400
  • 29
  • 193
  • 254
Alfe
  • 56,346
  • 20
  • 107
  • 159
  • 7
    Whilst this may theoretically answer the question, [it would be preferable](http://meta.stackexchange.com/q/8259) to include the essential parts of the answer here, and provide the link for reference. – Duncan Jones Nov 10 '13 at 19:35