I've had this code around for a while and had an opportunity to drag it out the other day and dust it off. The problem: Every now and again there's a situation where you don't really want to catch an exception, but you do want to perform some cleanup and let the exception propagate up the stack. Sometimes there's an extra wrinkle in that the cleanup code may itself throw an exception (that I'm simply going to assume we can ignore).
You can run the file to see the behavior. Simply provide an integer 1-5 as a command line argument and you'll run the selected scenario and see the output. The goal in this case is for cleanup to occur and an exception to be reported as having occurred at line 10.
The code in reraiser1 is wrong because this behaves as if a brand new exception were thrown at line 27. That may not seem so bad, but this code is pretty simple. If this happens and the stack trace is deep, it will be almost impossible to diagnose what went wrong.
The code in reraiser2 shows what happens when a second exception occurs in the except block. A bare raise statement here might be an attempt to re-raise the original exception, but python's rules about re-raising specify that the most recent exception in the scope is what is reraised. In this case, that's the exception thrown from the cleanup function. Again, this makes troubleshooting difficult.
In reraiser3 I worked around the problem in reraiser2 by moving the cleanup function's exception into a separate scope by defining a local cleanup function and calling it from within the except block. This prevents the cleanup function's exception from polluting the scope with an irrelevant exception and we can re-raise the original exception. This results in a stack trace rooted at line 10.
Reraiser4 takes a different approach. Instead of moving the cleanup function's exception into a separate scope, it captures the traceback information from the original exception and then passes it back to the raise statement so that the reported traceback is accurate.
The cleanest way to handle this is to use a finally block as shown in reraiser5. This situation is what "finally" is meant for: it does not trap the exception, it just gives you a chance to clean up before control moves back up the stack to the caller. The presence of finally clues readers in to the fact that you aren't messing with the exception, and that the point of the block is to perform cleanup.
Kindly drop me a note if I've got something wrong above, or if I'm missing a technique (or a common anti-pattern!). Thanks.