pythonproxy-pattern

Python proxy class


I'm trying to create a Proxy class to another class. I want this class to be passed into the proxy in its constructor and then for the proxy to dynamically create all the same methods of this class on itself.

This is what I hvae so far which is not working:

import inspect
from optparse import OptionParser

class MyClass:

    def func1(self):
        print 'MyClass.func1'


    def func2(self):
        print 'MyClass.func1'


class ProxyClass:

    def __init__(self):
        myClass = MyClass()
        members = inspect.getmembers(MyClass, predicate=inspect.ismethod)
        for member in members:
            funcName = member[0]
            def fn(self):
                print 'ProxyClass.' + funcName
                return myClass[funcName]()
            self.__dict__[funcName] = fn

proxyClass = ProxyClass()
proxyClass.func1()
proxyClass.func2()

I think it is the line self.__dict__[funcName] = fn that needs to be changed but am not sure what to?

I'm new to Python so if there is a completely different Pythonic way of doing this I would be happy to hear about that too.


Solution

  • I would not explicitly copy the methods of the wrapped class. You can use the magic method __getattr__ to control what happens when you call something on the proxy object, including decorating it as you like; __getattr__ has to return a callable object, so you can make that callable do whatever you need to (in addition to calling the original method).

    I have included an example below.

    class A:
        def foo(self): return 42
        def bar(self, n): return n + 5
        def baz(self, m, n): return m ** n
    
    class Proxy:
        def __init__(self, proxied_object):
            self.__proxied = proxied_object
    
        def __getattr__(self, attr):
            def wrapped_method(*args, **kwargs):
                print("The method {} is executing.".format(attr))
                result = getattr(self.__proxied, attr)(*args, **kwargs)
                print("The result was {}.".format(result))
                return result    
            return wrapped_method
    
    proxy = Proxy(A())
    proxy.foo()
    proxy.bar(10)
    proxy.baz(2, 10)