Proxy Design Advice Needed

2005-05-11 Thread nitrogenycs
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


Re: Proxy Design Advice Needed

2005-05-12 Thread nitrogenycs
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

-- 
http://mail.python.org/mailman/listinfo/python-list


Type question

2005-05-17 Thread nitrogenycs
Hello,

is this call assumed to be True in any case?

result = type(SomeClass) is SomeClass

I've written a proxy class which shadows a real object. If you call
type(proxyobj) it returns the type of the proxyobject and not the type
of the shadowed object. Example:

p = proxy(shadowobj())
result1 = type(p) is shadowobj # will return False
result2 = isinstance(p, shadowobj)   # will return True

So the first call compares the id()s of both types, while the second
calll seems to work different.
I've tried to use a proxy metaclass that creates new objects with the
name 'shadowobj'. So

print type(p)
print type(shadowobj())

will look exactly the same. however their id()s compare different and
that's why the 1st test doesn't work as I'd expect it to work.
Can somebody tell me why the id()s compare different for the same type
names? Here's the metaclass:

class ProxyMeta(type):
def __new__(self, classname, bases, classdict):
return type.__new__(self, 'shadowobj', bases, classdict)

class Proxy(object):
__metaclass__ = ProxyMeta

Why is (type(Proxy) is shadowobj == False)? Shouldn't type.__new__
reuse the existing shadowobj type and increase its refcount instead of
creating a new instance of it? Then the id()s would compare the same.
So, finally, is checking for types with 'is' as shown above just wrong
and one should use isinstance or is my proxy class showing bad
behaviour or is this a bug in type.__new__?

-Matthias

-- 
http://mail.python.org/mailman/listinfo/python-list