Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Undo in Python with a very large state. Is it possible?

Tags:

undo

python

This appears simple, but I can't find a good solution.

It's the old 'pass by reference'/ 'pass by value' / 'pass by object reference' problem. I understand what is happening, but I can't find a good work around.

I am aware of solutions for small problems, but my state is very large and extremely expensive to save/ recalculate. Given these constraints, I can't find a solution.

Here is some simple pseudocode to illustrate what I would like to do (if Python would let me pass by reference):

class A:
    def __init__(self,x):
        self.g=x
        self.changes=[]
    def change_something(self,what,new): # I want to pass 'what' by reference
        old=what # and then de-reference it here to read the value
        self.changes.append([what,old]) # store a reference
        what=new # dereference and change the value
    def undo_changes():
        for c in self.changes:
            c[0]=c[1] # dereference and restore old value

Edit: Adding some more pseudocode to show how I would like the use the above

test=A(1) # initialise test.g as 1

print(test.g)
out: 1

test.change_something(test.g,2)
# if my imaginary code above functioned as described in its comments,
# this would change test.g to 2 and store the old value in the list of changes

print(test.g)
out: 2

test.undo_changes()

print(test.g)
out: 1

Obviously the above code doesnt work in python due to being 'pass by object reference'. Also I'd like to be able to undo a single change, not just all of them as in the code above.

The thing is... I can't seem to find a good work around. There are solutions out there like these:

Do/Undo using command pattern in Python

making undo in python

Which involve storing a stack of commands. 'Undo' then involves removing the last command and then re-building the final state by taking the initial state and re-applying everything but the last command. My state is too large for this to be feasible, the issues are:

  • The state is very large. Saving it entirely is prohibitively expensive.
  • 'Do' operations are costly (making recalculating from a saved state infeasible).
  • Do operations are also non-deterministic, relying on random input.
  • Undo operations are very frequent

I have one idea, which is to ensure that EVERYTHING is stored in lists, and writing my code so that everything is stored, read from and written to these lists. Then in the code above I can pass the list name and list index every time I want to read/write a variable.

Essentially this amounts to building my own memory architecture and C-style pointer system within Python! This works, but seems a little... ridiculous? Surely there is a better way?

like image 346
Ben Avatar asked Mar 26 '26 01:03

Ben


1 Answers

Please check if it helps....

class A:
def __init__(self,x):
    self.g=x
    self.changes={}
    self.changes[str(x)] = {'init':x, 'old':x, 'new':x}   #or make a key by your choice(immutable)
def change_something(self,what,new): # I want to pass 'what' by reference
    self.changes[what]['new'] = new #add changed value to your dict
    what=new # dereference and change the value
def undo_changes():
    what = self.changes[what]['old'] #retrieve/changed to the old value
    self.changes[what]['new'] = self.changes[what]['old'] #change latest new val to old val as you reverted your changes

for each change you can update the change_dictionary. Onlhy thing you have to figure out is "how to create entry for what as a key in self.change dictionary", I just made it str(x), just check the type(what) and how to make it a key in your case.

like image 163
Satya Avatar answered Mar 27 '26 16:03

Satya



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!