0

My python code looks something like this -

try:
    statement1
    statement2
    statement3
except Exception:
    handleException

The problem is, if statement3 produces an exception, the effects of statement1 and statement2 have already taken place, and I can't undo them in the except section. Is there an easy way to write something like -

check if the following block runs without exceptions:
    statement1
    statement2
    statement3
if yes:
    run entire block
if no:
    handleException

(Basically something like transactional atomicity for Python code).

Russia Must Remove Putin
  • 374,368
  • 89
  • 403
  • 331
Ankush Jain
  • 487
  • 2
  • 14
  • 10
    In general, no. What if what statement1 does is send data to an online server? There's no way to "undo" that. In general many things that might be done are not undoable, or are nontrivial to undo. How to rollback an action depends totally on what that action was. – BrenBarn Sep 17 '14 at 18:26
  • Transaction management is not trivial; there is no standard Python construct that'll do that for you. – Martijn Pieters Sep 17 '14 at 18:28
  • 1
    You want `print` statements to be unprinted? Files to be undeleted? – kindall Sep 17 '14 at 18:29
  • 2
    "Don't gamble; take all your savings and buy some good stock, and hold it till it goes up, then sell it. If it don't go up, don't buy it." - Will Rogers – Russia Must Remove Putin Sep 17 '14 at 18:33
  • I wasn't thinking of statement1/2/3 as particularly complex statements. Upon reading BrenBarn's comment, I realized what I just asked for is non-trivial. – Ankush Jain Sep 17 '14 at 18:55

2 Answers2

3

What you're asking is to have Python do something to see if it works, then do it, else, not do it in the first place. This violates causality.

To handle this sort of issue, we typically use context managers, for example:

with db.transaction():
    entire_block()

which should handle the rolling back part for you in the event of an exception, if they're well written.

Russia Must Remove Putin
  • 374,368
  • 89
  • 403
  • 331
1

With a specific arbitrary statement, no.

If you have to have granular undo like that, you're better off writing the items in the block using the Command pattern, stacking an undo operation for each operation as you proceed. If you get to the end and it's all OK, you wipe the stack, dropping all the undos; if you had an exception, you pop the undos off the stack one by one and execute them in reverse to restore the original state.

Joe McMahon
  • 3,266
  • 21
  • 33