指定抽象函数的退出函数

时间:2014-04-28 11:09:35

标签: python interface atexit

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

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"

我需要一种在method2执行后自动调用Amethod1的方法(应该在类A方面完成 - 独立于继承的类)。

这样做有什么好办法吗?

3 个答案:

答案 0 :(得分:3)

您可以使用元类,它在创建类时包装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"

这适用于创建(子)类时基本上是特定方法的装饰器。

另一种方法,有点hackish,是截取方法访问,但会工作。您在__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() decorator,包装器会保留包装方法中的几个重要属性,例如名称和文档字符串。

答案 1 :(得分:1)

这看起来像是Template method模式的工作,例如:

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"

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

答案 2 :(得分:1)

当出现这种情况时,通常可以通过覆盖“更深层次”功能来解决。

不要让class B覆盖method1,而是覆盖method1_subfunction,并从method1_subfunction method2和method1 >

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"