On Fri, Jan 30, 2015 at 3:00 AM, Marko Rauhamaa <ma...@pacujo.net> wrote: > Marko Rauhamaa <ma...@pacujo.net>: > >>>> Surprisingly this variant could raise an unexpected exception: >>>> >>>> ============================== >>>> try: >>>> do_interesting_stuff() >>>> except ValueError: >>>> try: >>>> log_it() >>>> finally: >>>> raise >>>> ============================== >>>> >>>> A Python bug? >> [...] >> My Python did do exception chaining, but the problem is the surface >> exception changes, which could throw off the whole error recovery. > > BTW, the code above can be fixed: > > ============================== > try: > do_interesting_stuff() > except ValueError as e: > try: > log_it() > finally: > raise e > ============================== > > Now the surface exception is kept and the subsidiary exception is > chained to it. > > I'm a bit baffled why the two pieces of code are not equivalent.
The bare raise re-raises the most recent exception that is being handled. The "raise e" raises that exception specifically, which is not the most recent in the case of a secondary exception. Note that the exceptions are actually chained *in reverse*; the message falsely indicates that the secondary exception was raised first, and the primary exception was raised while handling it, e.g.: Traceback (most recent call last): File "<stdin>", line 5, in <module> TypeError During handling of the above exception, another exception occurred: Traceback (most recent call last): File "<stdin>", line 7, in <module> File "<stdin>", line 2, in <module> ValueError That's because "raise e" causes the exception e to be freshly raised, whereas the bare "raise" merely makes the existing exception context active again. It's interesting to note here that although the exception retains its original traceback information (note the two separate lines in the traceback), it is not chained again from the TypeError. One might expect to actually see the ValueError, followed by the TypeError, followed by the ValueError in the chain. That doesn't happen because the two ValueErrors raised are actually the same object, and Python is apparently wise enough to break the chain to avoid an infinite cycle. -- https://mail.python.org/mailman/listinfo/python-list