Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

changes inside try-except persist after exception is caught



Since I've learned of exception-handling the first time (not in Python), I was under the impression that when you begin a try block, it's like you start writing in a sandbox: if an exception occurs, everything that happened inside the try block will be like it never happened. To my naive surprise, I noticed this isn't true, or not in the way I thought, at least in Python. Here's my experiment in Python:

>>> a = range(5)
>>> a
[0, 1, 2, 3, 4]
>>> try:
...     a.append(5)
...     oops
... except:
...     raise
... 
Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
NameError: name 'oops' is not defined
>>> print a
[0, 1, 2, 3, 4, 5]

As you can see, I changed the list inside the try block, then trigger an error, which is raised. I was expecting to see the list in its original form, [0, 1, 2, 3, 4], but the a.append(5) persisted.

Were my expectations wrong in the first place? Maybe partially wrong expectations(there may be a sandbox, but it doesn't act like that)?

like image 543
CamilB Avatar asked Jan 20 '11 20:01

CamilB


People also ask

Is it possible to execute the code in the try block again after an exception in caught in catch block?

If the exception occurs, and nothing is done to resolve the underlying cause, there is no retry counter or such to stop the loop.

Does try except continue?

With try and except , even if an exception occurs, the process continues without terminating.

How do you continue if exception occurs in Python?

If an exception occurs during execution of the try clause, the rest of the clause is skipped. Then, if its type matches the exception named after the except keyword, the except clause is executed, and then execution continues after the try/except block.

How do I continue an exception?

By putting a BEGIN-END block with an exception handler inside of a loop, you can continue executing the loop if some loop iterations raise exceptions. You can still handle an exception for a statement, then continue with the next statement. Place the statement in its own subblock with its own exception handlers.


2 Answers

You just discovered that exceptions are not a silver bullet for error handling.

Exceptions do not protect you from state changes... whatever was completed without errors before the exception is thrown will have to be undone. This is how exception work in Python, C++, Java and many other languages as well.

Sometimes you may have a sort of "external" general protection: for example if all you do is changes to a database that supports transactions then you can have the top-level catching statement to do a "rollback" instead of committing the changes and you get the protection you're looking for. If there is no such a natural "wall" protecting from partial state change then things are much more difficult to handle correctly.

The very reason that operations that have been completed will not be undone is what makes the use of exceptions not trivial as the complexity of the problems scales up.

Normally code can be classified exception "safe" at several levels:

  1. In case of an exception everything is ruined and not even a clean exit or restart is possible. This is what is normally classified as NOT exception safe.

  2. In case of an exception the code will not complete its job, and the state of the subsystem (class instance, library) is invalid. You however can restart safely (e.g. you can destroy the instance or reinitialize the library). This is the very minimum exception safety.

  3. In case of an exception the code will not complete its job, and the state of the subsystem will be valid but unspecified. The calling code may try to inspect the current state and keep using the subsystem instead of reinitializing it, for example. Just a little better than 2.

  4. In case of an exception the code will do nothing, leaving the program state untouched. So either the request is completed without errors or an error signal is returned to the caller and nothing has been altered. This is of course the best behavior.

The biggest problem with exception handling is that even if you have two very safe type-4 pieces A and B still the simple sequential composition AB is not safe because in case of a problem in B you must also undo whatever A has completed. Also if it's possible to get an exception when performing 1/A (i.e. when un-doing what A was able to complete) then you're in BIG trouble, because you cannot neither do B, nor restoring the state as it was before (this means it's just impossible to implement AB as a type-4 operation).

In other words good bricks won't make trivial making good constructions (in respect to exception safety).

like image 194
6502 Avatar answered Oct 05 '22 04:10

6502


Your expectation is wrong in just about any language that supports exceptions - there is no all-or-nothing semantics associated with try blocks (although you may have transactional concepts in some languages, e.g. if there is support for transactional memory).

It's only that the part of the try block after the exception is not executed anymore.

like image 37
Martin v. Löwis Avatar answered Oct 05 '22 02:10

Martin v. Löwis