Question

I found this recipe to create a proxy class. I've used it to wrap a custom object and would like to overload certain properties and also attach new attributes to the proxy. However, when I call any method on the proxy (from within the proxy class), I end up being delegated to the wrappee which is not what I want.

Is there any way of accessing or storing a reference to the proxy?

Here's some code (untested) to demonstrate the problem.

class MyObject(object):
  @property
  def value(self):
    return 42

class MyObjectProxy(Proxy): # see the link above
  def __getattribute__(self, attr):
    # the problem is that `self` refers to the proxied 
    # object and thus this throws an AttributeError. How 
    # can I reference MyObjectProxy.another_value()?
    if attr == 'value':  return self.another_value() # return method or attribute, doesn't matter (same effect)
    return super(MyObjectProxy, self).__getattribute__(attr)

  def another_value(self):
    return 21

o = MyObject()
p = MyObjectProxy(o)
print o.value
print p.value

In a sense my problem is that the proxy works too good, hiding all its own methods/attributes and posing itself as the proxied object (which is what it should do)...

Update

Based on the comments below, I changed __getattribute__ to this:

def __getattribute__(self, attr):
    try:
        return object.__getattribute__(self, attr)
    except AttributeError:
        return super(MyObjectProxy, self).__getattribute__(attr)

This seems to do the trick for now, but it would be better to add this directly to the Proxy class.

Was it helpful?

Solution

The reason that your code goes wrong is the loop in __getattribute__. You want to override __getattribute__ so you can reach certain properties in the proxy class itself. But let's see.

When you call p.value the __getattribute__ is called. Then it comes here if attr == 'value': return self.another_value(). Here we need to call another_value so we enter __getattribute__ again.

This time we comes here return super(MyObjectProxy, self).__getattribute__(attr). We call the Proxy's __getattribute__, and it tries to fetch another_value in Myobject. So the exceptions occur.

You can see from the traceback that we finally goes to return super(MyObjectProxy, self).__getattribute__(attr) that should not go to.

Traceback (most recent call last):
  File "proxytest.py", line 22, in <module>
    print p.value
  File "proxytest.py", line 13, in __getattribute__
    if attr == 'value':  return self.another_value() # return method or attribute, doesn't matter (same effect)
  File "proxytest.py", line 14, in __getattribute__
    return super(MyObjectProxy, self).__getattribute__(attr)
  File "/home/hugh/m/tspace/proxy.py", line 10, in __getattribute__
    return getattr(object.__getattribute__(self, "_obj"), name)
AttributeError: 'MyObject' object has no attribute 'another_value'

edit:
Change the line of code if attr == 'value': return self.another_value() to if attr == 'value': return object.__getattribute__(self, 'another_value')().

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top