【问题标题】:Specifying an exit function for an abstract function为抽象函数指定退出函数
【发布时间】:2014-06-13 21:46:36
【问题描述】:

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

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"

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

有什么好的方法吗?

【问题讨论】:

  • 因为你继承自A,你可以简单地调用self.method2()。
  • 听起来你想在你的 API 中记录任何实现method1 的人必须在最后调用覆盖的版本,或者在最后直接调用self.method2。或者要求method1 的实现者使用装饰器。
  • 我想在A班做所有事情
  • @MartijnPieters - 完全正确,但在某种程度上它与继承的类是透明的

标签: python interface atexit


【解决方案1】:

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

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

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

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,包装器维护了被包装方法的几个重要属性,例如它的名称和文档字符串。

【讨论】:

  • 确实很老套,但很聪明。
  • @schmi: 你可以让MetaA继承自abc.ABCMeta。
【解决方案2】:

这看起来像是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"

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

【讨论】:

    【解决方案3】:

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

    不要让class B覆盖method1,而是让它覆盖method1_subfunction,并从method1同时调用method1_subfunction和method2

    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"
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-02
      • 2013-04-11
      • 1970-01-01
      • 2016-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-01
      相关资源
      最近更新 更多