4

我需要一种从抽象方法调用函数的方法,即

class A(object):

      @abc.abstractmethod
      def method1(self):
           raise Exception("Unimplemented method")

      def method2(self):
           print "method1 finished"

class B(A):
     def method1(self):
         print "executing method1 from class B"

我需要一种在执行之后自动调用method2class的方法(它应该在类端完成 - 独立于继承的类)。Amethod1A

有这样做的好方法吗?

4

3 回答 3

4

您可以使用在method1创建类时包装的元类:

from functools import wraps

class MetaA(type):
    def __new__(meta, name, bases, attr):
        method1 = attr['method1']
        if not getattr(method, '__isabstractmethod__'):
            @wraps(method1)
            def wrapper(self, *args, **kw):
                res = method1(self, *args, **kw)
                self.method2()
                return res
            attr['method1'] = wrapper
        return super(MetaA, meta).__new__(meta, name, bases, attr)

class A(object):
     __metaclass__ = MetaA

     @abc.abstractmethod
     def method1(self):
         raise Exception("Unimplemented method")

     def method2(self):
         print "method1 finished"

每当创建(子)类时,这将基本上是装饰器应用于特定方法。

另一种有点骇人听闻的方法是拦截方法访问,但会起作用。您将实现一个添加包装器的__getattribute__钩子A

from functools import wraps

class A(object):
     @abc.abstractmethod
     def method1(self):
         raise Exception("Unimplemented method")

     def method2(self):
         print "method1 finished"

     def __getattribute__(self, name):
         obj = super(A, self).__getattribute__(name)
         if name == 'method1':
             @wraps(obj)
             def wrapper(*args, **kw):
                 res = obj()
                 self.method2()
                 return res
             return wrapper
         return obj

任何一种方法都会导致:

>>> B().method1()
executing method1 from class B
method1 finished

通过使用@functools.wraps()装饰器,包装器维护了被包装方法的几个重要属性,例如它的名称和文档字符串。

于 2014-04-28T11:15:18.330 回答
1

这看起来像是模板方法模式的工作,例如:

class A(object):
  def method1(self):
      # do something before
      try:
          self.method1_impl()
      finally:
          # do something after, for example:
          self.method2()

  @abc.abstractmethod
  def method1_impl(self):
      pass

  def method2(self):
      print "method1 finished"


class B(A):
    def method1_impl(self):
        print "executing method1 from class B"

虽然我不是这种风格的支持者(随着代码的增长和变得越来越复杂,它往往变得难以理解),但这种风格偶尔会被使用并且有权存在。

于 2014-04-28T11:21:56.287 回答
1

当这种情况发生时,通常可以通过覆盖“更深”的功能来解决。

而不是class B覆盖method1,使其覆盖method1_subfunction,并调用两者method1_subfunctionmethod2method1

class A(object):

    def method1(self):
        self.method1_subfunction()
        self.method2()

    @abc.abstractmethod
    def method1_subfunction(self):
        raise Exception("Unimplemented method")

    def method2(self):
        print "method1 finished"

class B(A):
    def method1_subfunction(self):
        print "executing method1 from class B"
于 2014-04-28T11:23:08.887 回答