Proxy Design Advice Needed
vincent wehren
vincent at visualtrans.de
Thu May 12 01:20:02 EDT 2005
<nitrogenycs at web.de> schrieb im Newsbeitrag
news:1115848303.630570.147840 at o13g2000cwo.googlegroups.com...
> 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
This may be help:
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/366254
--
Vincent Wehren
>
>
> 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)
>
More information about the Python-list
mailing list