3

I'm writing a class that wraps around an object of another class. The intend is to change some of its method behaviors while able to extend all of its other interfaces. I'm not using inheritance because the inner class object can die and outer class needs to be able to replace it with a live one without destroying itself.

so I have:

class Inner():
    def foo(): pass
    def goo(): pass

class Outer():
    self.inner = InnerFactory(innerType)
    def foo(): 
         try:
             self.inner.foo() 
         except:
             del self.inner
             self.inner = InnerFactory(innerType)
             self.inner.foo()

The question is how to extend goo w/o explicitly rewrite as I may have tons of other such methods I'm not aware of.

Actually after reading some of the feedbacks below, I realized I'm not using the great function getattr. However, I don't quite follow why the suggestions below all seem to use such a complicated version. Why can't it be as simple as:

def __getattr__( self, name ):
    if self.inner:
          return getattr( self.inner, name )
    else:
          raise Exception( 'attribute %s not found' % name ) 
ansetou
  • 1,531
  • 1
  • 9
  • 5

2 Answers2

3

Something like the code below does what you want, but: 1) it is ugly; 2) it is not thread safe; 3) it falls into a loop until some method from Inner raises an exception (this is not due to the implementation but due to the initial idea posted); 4) some more reasons to avoid using it :)

class Inner:
  def foo(self):
    print "foo"
  def bar(self):
    print "bar"

class Outer:
  def __init__(self):
    self.inner = Inner()

  def __getattr__(self, name):
    ret = getattr(self.inner, name)
    def wrapper(*args):
      try:
        ret(*args)
      except:
        del self.inner
        self.inner = Inner()
        updated = self.__getattr__(name)
        updated(*args)

    return wrapper

  def blah(self):
    print "Blah"

outer = Outer()

outer.foo()
outer.bar()
outer.blah()
outer.nosuchattr()
khachik
  • 28,112
  • 9
  • 59
  • 94
  • Isn't `except:` some kind of pythonic-wise heresy? Shouldn't we catch only `AttributeError`s? – Evpok May 24 '11 at 14:50
0

My solution is similar to @khachik plus some method caching.

  • Be careful it's easy to get into infinite loop with __ getattr__.
  • Also you may want to add threading locks if needed

Code is untested treat it as pseudo code.

class Outer(object):
    def __init__(self):
        self.method_cache = {}
        self.methods_to_override = ['foo', 'goo']

    def __getattr__(self, method_name):
        if method_name in self.methods_to_override:
            if method_name in self.method_cache:
                return self.method_cache[method_name]
            else:
                def wrapper(*args, **kw):
                    wrapped = getattr(self.inner, method_name)
                    try:
                        return wrapped(*args, **kw)
                    except InnerDiedError:
                        self.inner = self.InnerFactory(innerType)
                        wrapped = getattr(self.inner, method_name)
                        return wrapped(*args, **kw)

                self.method_cache[method_name] = wrapper
                return wrapper
Shekhar
  • 7,095
  • 4
  • 40
  • 45