snoe wrote:
> I have a suspicion that there's an easier way to do this than > explicitly adding a Project.pickleme() call to the beginning of all of > my set/add methods. > So is there a way to wrap methods for this type of functionality or is > there another way of doing this, maybe without using setter methods? I guess you are pointing to decorators, anyway you have to explicitly wrap methods that are supposed to pickle. Another way around is implement a metaclass and give the pickling methods a special start name like set_ or add_ ,so having a protocol for writing methods names.I paste the __metaclass__ solution #### this is a skeleton def saveStateWrapper(method,states): from copy import copy def wrapper(self,*_,**__): self.__undoings.append(map(copy,[getattr(self,state) for state in states])) # copy can not be idoneous return method(self,*_,**__) return wrapper def initWrapper(init): def wrapper(self,*_,**__): self.__undoings=[] init(self,*_,**__) return wrapper def undo(self): # an undoing method if self.__undoings: for state,was in zip(self.states,self.__undoings.pop(-1)): setattr(self,state,was) class Undoable(type): # the metaclass def __init__(cls,name,bases,attrs): cls.__init__=initWrapper(cls.__init__) # wrap init to add an attribute __undoings to the instances for attr in dir(cls): if attr.split('_')[0] in ('add','set'): # look for attributes protocolleds setattr(cls,attr,saveStateWrapper(getattr(cls,attr),cls.states)) # wrap methods cls.undo=undo #add the undo method class Project(object): __metaclass__=Undoable states=['pname','devices'] def __init__(self,pname): self.devices = set() self.pname = pname def set_pname(self,pname): self.pname = pname def lookFor(self,dname): # names can change in the devices instances for device in self.devices: # add exceptions checkings if device.dname==dname: return device def add_device(self,dname): self.devices.add(Device(self,dname)) class Device(object): __metaclass__=Undoable states=['dname'] def __init__(self,parent,dname): self.parent = parent self.dname = dname def set_dname(self,dname): self.dname = dname project=Project('pippo') project.set_pname('pupo') assert project.pname=='pupo' project.undo() assert project.pname=='pippo' project.add_device('aargh') device=project.lookFor('aargh') device.set_dname('sperem') assert device==project.lookFor('sperem') device.undo() assert device==project.lookFor('aargh') ## :) project.undo() -- http://mail.python.org/mailman/listinfo/python-list