Hello, I need a way to get a notification whenever a variable of an object changes. The approach should be non-intrusive so that I can use existing objects without modifying them. I want to be notified no matter who or what did change the wrapped object - even whenever an object internal methods changes the variables. So I coded the piece of code shown below (just copy and paste it, it's ready-to-run). It's basically a Proxy class that takes an object and whenever somebody tries to access the proxy, the proxy forwards this to the real object. Whenever a method of the obj gets called the proxy detects this and the operation is performed on the the proxy object so that variable change notifications can be send. Since I am quite new to Python and the code does not 100% what I want, I have the feeling, it's not optimal and that there might be a better way to achieve what I want. For example I am not sure if really all changes will be catched this way and if the method call re-routed to proxy object is not a bit hackish. Second, type(Proxy()) doesn't return the same as type(WrappedObj()). The proxy should behave identical to the wrapped object. Should I do this with metaclasses to get the type right or are there better ways? I am not sure if they could fit here or not. So, what do you think of this code and how should I improve it?
Thanks a lot for your help! -Matthias Code (just copy and pasts and it should run): import inspect, new, sys class Proxy(object): def __init__(self, wrappedObj): # need to call object here to save objs to our own dict object.__setattr__(self,'_wrappedObj',wrappedObj) object.__setattr__(self,'_observers',{}) def __getattribute__(self, name): # if attribute of proxy obj itself was queried return that value if name in ['_wrappedObj','_observers','Subscribe','Notify']: return object.__getattribute__(self, name) # otherwise get var from the wrapped object attr = getattr( object.__getattribute__(self, '_wrappedObj'), name ) # make method use this proxy object instead of wrapped one to catch updates if inspect.ismethod( attr ): return new.instancemethod( attr.im_func, self, attr.im_class ) else: return attr def __setattr__(self, name, value): # sets attribute of the wrapped value setattr(object.__getattribute__(self,'_wrappedObj'), name, value) # notify me of change object.__getattribute__(self,'Notify')('Changed',name, value) # Adds an observer def Subscribe(self, function, event = ''): self._observers.setdefault(event,[]).append(function) # Notifies all observers def Notify(self, event = '', *args): for observer in self._observers.get(event, []): observer(*args) class TestObj(object): classVar = 'cv' def __init__(self): self.spam = '1' def method(self): self.spam = '2' # create a proxy p = Proxy(TestObj()) # print some info of it print 'Proxy: %s ' % p print 'Class of proxy: %s' % p.__class__ print 'Type of proxy: %s <--- this sucks' % type(p) print 'Dir of proxy: %s' % dir(p) # enable watching changes p.Subscribe(lambda name, var: sys.stdout.write('%s was changed and is now %s\n' % (name,var) ) ,'Changed') # change some stuff p.method() p.cv = 'new cv' p.spam = 1 p.func = lambda x: x-1 print p.func(2) -- http://mail.python.org/mailman/listinfo/python-list