Proxy Design Advice Needed

Discussion in 'Python' started by nitrogenycs@web.de, May 11, 2005.

  1. Guest

    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)
     
    , May 11, 2005
    #1
    1. Advertising

  2. <> schrieb im Newsbeitrag
    news:...
    > 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)
    >
     
    vincent wehren, May 12, 2005
    #2
    1. Advertising

  3. Guest

    Thanks for the hint so far!
    The recipe shown there does not exactly what I want though, it doesn't
    do the type() stuff and it hooks up every _ variable which could get
    crucial if the wrapped object's methods uses them too.

    So I think my question boils down to how I can make type(Proxy) return
    type(WrappedObject)?

    Any hints?

    -Matthias
     
    , May 12, 2005
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. vidy5300
    Replies:
    0
    Views:
    874
    vidy5300
    Jun 7, 2004
  2. SpOiLeR
    Replies:
    6
    Views:
    406
    SpOiLeR
    Feb 17, 2005
  3. Replies:
    0
    Views:
    1,646
  4. Karsten Wutzke
    Replies:
    1
    Views:
    881
    Steven Simpson
    Aug 20, 2007
  5. mazdotnet

    Professional design advice needed

    mazdotnet, Apr 30, 2008, in forum: ASP .Net
    Replies:
    3
    Views:
    260
    Fernando Rodriguez
    May 2, 2008
Loading...

Share This Page