Wrapping a class set method

Paolino paolo.veronelli at gmail.com
Thu Jul 28 00:29:02 CEST 2005


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()




More information about the Python-list mailing list