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