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()
___________________________________
Yahoo! Mail: gratis 1GB per i messaggi e allegati da 10MB
http://mail.yahoo.it