Как написать класс контейнера / оболочки, который адаптируется к интерфейсу класса члена? - PullRequest
2 голосов
/ 24 мая 2011

Я пишу класс, который оборачивается вокруг объекта другого класса. Намерение состоит в том, чтобы изменить некоторые из его методов поведения, в то же время способный расширить все другие его интерфейсы. Я не использую наследование, потому что внутренний объект класса может умереть, а внешний класс должен иметь возможность заменить его живым без разрушения самого себя.

так у меня есть:

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()

Вопрос в том, как расширить goo без явной перезаписи, поскольку у меня может быть множество других подобных методов, о которых я не знаю.

На самом деле, прочитав некоторые отзывы ниже, я понял, что не использую отличную функцию getattr . Однако я не совсем понимаю, почему приведенные ниже предложения, похоже, используют такую ​​сложную версию. Почему это не может быть так просто, как:

def __getattr__( self, name ):
    if self.inner:
          return getattr( self.inner, name )
    else:
          raise Exception( 'attribute %s not found' % name ) 

Ответы [ 2 ]

2 голосов
/ 24 мая 2011

Что-то вроде приведенного ниже кода делает то, что вы хотите, но: 1) это уродливо;2) это не потокобезопасный;3) он попадает в цикл до тех пор, пока какой-то метод из Inner не вызовет исключение (это не из-за реализации, а из-за опубликованной первоначальной идеи);4) еще несколько причин избегать его использования:)

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()
0 голосов
/ 24 мая 2011

Мое решение похоже на @khachik плюс некоторые методы кеширования.

  • Будьте осторожны, с __ getattr__ легко попасть в бесконечный цикл.
  • Также вы можете добавить блокировку потоков, если это необходимо

Код не проверен, трактуйте его как псевдокод.

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
...