orange orange - 9 months ago 51
Python Question

Proxy object in Python

I'm looking for way to pass method calls through from an object (wrapper) to a member variable of an object (wrappee). There are potentially many methods that need to be externalised, so a way to do this without changing the interface of the wrapper when adding a method to the wrappee would be helpful.

class Wrapper(object)
def __init__(self, wrappee):
self.wrappee = wrappee

def foo(self):
return 42

class Wrappee(object):
def bar(self):
return 12

o2 = Wrappee()
o1 = Wrapper(o2)

o1.foo() # -> 42
o1.bar() # -> 12
o1.<any new function in Wrappee>() # call directed to this new function


It would be great if this call redirection is "fast" (relative to a direct call, i.e. not adding too much overhead).

Answer Source

A somewhat elegant solution is by creating an "attribute proxy" on the wrapper class:

class Wrapper(object):
    def __init__(self, wrappee):
        self.wrappee = wrappee

    def foo(self):
        print 'foo'

    def __getattr__(self, attr):
        try:
            super(Wrapper, self).__getattr__()
        except AttributeError as e:
            return getattr(self.wrappee, attr)


class Wrappee(object):
    def bar(self):
        print 'bar'

o2 = Wrappee()
o1 = Wrapper(o2)

o1.foo()
o1.bar()

all the magic happens on the __getattr__ method of the Wrapper class, which will try to access the method or attribute on the Wrapper instance, and if it doesn't exist, it will try on the wrapped one.

if you try to access an attribute that doesn't exist on either classes, you will get this:

o2.not_valid
Traceback (most recent call last):
  File "so.py", line 26, in <module>
    o2.not_valid
  File "so.py", line 15, in __getattr__
    raise e
AttributeError: 'Wrappee' object has no attribute 'not_valid'