views:

158

answers:

2

Consider the following code:

try:
    raise Exception("a")
except:
    try:
        raise Exception("b")
    finally:
        raise

This will raise Exception: a. I expected it to raise Exception: b (need I explain why?). Why does the final raise raise the original exception rather than (what I thought) was the last exception raised?

+2  A: 

On python2.6

I guess, you are expecting the finally block to be tied with the "try" block where you raise the exception "B". The finally block is attached to the first "try" block.

If you added an except block in the inner try block, then the finally block will raise exception B.

try:
  raise Exception("a")
except:
  try:
    raise Exception("b")
  except:
    pass
  finally:
    raise

Output:

Traceback (most recent call last):
  File "test.py", line 5, in <module>
    raise Exception("b")
Exception: b

Another variation that explains whats happening here

try:
  raise Exception("a")
except:
  try:
    raise Exception("b")
  except:
    raise

Output:

Traceback (most recent call last):
  File "test.py", line 7, in <module>
    raise Exception("b")
Exception: b

If you see here, replacing the finally block with except does raise the exception B.

pyfunc
I have come to the same conclusion.
klausbyskov
Indeed, this works! I'd have never guessed. Is this documented somewhere? Is this a feature or is it a necessity that comes from issues in the grammar?
wilhelmtell
Why doesn't the second exception merely shadow the first? I wish Python would err for syntax, or at least warn me about this.
wilhelmtell
wilhelmtell: `raise` is re-raising the last exception you caught, not the last exception you raised. If you try `raise` by itself after throwing an exception and you haven't previously caught any exceptions, you'll get a TypeError since there's nothing to re-raise.
Wooble
@wilhelmtell: I guess the doc may provide some answer to this. This does seem to have been corrected in Python 3. The behavior is different. Link : http://docs.python.org/reference/compound_stmts.html#the-try-statement
pyfunc
A: 

raise is re-raising the last exception you caught, not the last exception you raised

Reposting this as an answer since I think it's pretty important and will get lost in the comments.

Falmarri