【问题标题】:Define an abstract method but require a subclass implementation定义抽象方法但需要子类实现
【发布时间】:2015-08-19 20:14:41
【问题描述】:

注意我不认为 abc 本质上解决了我正在寻找的问题。以另一种可能更好的方式重述,我正在寻找一种方法来部分实现 Parent.method,但也需要有一个 Subclass.method,它使用并添加到部分 Parent.method 实现。

我想部分定义一个抽象类方法,但仍然要求该方法也在子类中实现。例如:

class AbstractClass(object):
    def amethod():
        # some code that should always be executed here
        vars = dosomething()

        # But, since we're the "abstract" class
        # force implementation through subclassing
        if <somehow determine whether this has not been subclassed>:
            raise NotImplementedError

class ActualClass(AbstractClass):
    def amethod():
        # Actual class code
        code_here()

        # And execute the super class code.
        super(ActualClass, self).amethod()

【问题讨论】:

  • 为什么你需要更多实际上什么都不做的类?
  • Abstract methods in Python 的可能重复项
  • @TigerhawkT3 这就是我想要做上述事情的原因。我确实希望它做一些事情,但是每个子类都应该发生一些事情。只是没有子类,部分是没有意义的。问这个问题的一部分是被告知“是的,这很糟糕,这样做你想做的事......”然而,到目前为止,这还没有发生。
  • 这并不是说它不好(即产生错误或数据丢失),而是它可能是不必要的并且在很大程度上无法执行。如果有人出现并创建了一个子类,而该子类只不过是超类的包装器呢?
  • 虽然我的特殊情况这不是问题,但这种方法肯定无法针对确定的执行。为此,我认为唯一真正的解决方案是通过 API 调用,其中 API 将强制执行额外的行为。虽然也可以使用一些元编程方法。

标签: python


【解决方案1】:

您可以通过在父级中引发异常来强制它:

class base(object):
    def a_method(self):
        raise NotImplementedError("Implement this!")

class second(base):
    pass

如果我打电话给second().a_method(),我会得到一个例外。 Python 中没有抽象之类的东西,但这可能是你最好的方法。否则,

import abc
class base(object):
    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    def something_to_implement(this):
        """A docstring"""
        return

如果已初始化,这将通过尝试引发 TypeError 来使方法“抽象”。

【讨论】:

    【解决方案2】:

    像这样测试?

    class AbstractClass(object):
        def amethod(self):
            # some code that should always be executed here
            print(" AbstractClass.amethod()")
    
            # But, since we're the "abstract" class
            # force implementation through subclassing
            if self.__class__ == AbstractClass:
                raise NotImplementedError
    
    class ActualClass(AbstractClass):
        def amethod(self):
            # Actual class code
            print(" ActualClass.amethod()")
    
            # And execute the super class code.
            super(ActualClass, self).amethod()
    
    
    #a = AbstractClass()
    #a.amethod()
    
    b = ActualClass()
    b.amethod()
    

    【讨论】:

    • 我假设您希望 self 在函数 arg 列表中,或者这些将是静态方法还是其他?
    • 嗯,这必须被继承并且必须在__init__
    • 看看这是否符合您的要求。 (只需将其更改为顶部,使其也可以在 python 3 中工作)。
    • 这将按照我的想法实现这个概念。一直忘记class。就我的目的而言就足够了。
    • 这个答案并不强制在子类中实现该方法。如果用户没有在 ActualClass 中实现方法,检查仍然会通过,因为 b.__class__ 将是 ActualClass,而不是 AbstractClass。
    【解决方案3】:

    这也很有趣

    def abstractmethod(method):
        def default_abstract_method(*args, **kwargs):
            raise NotImplementedError('call to abstract method ' + repr(method))    
        default_abstract_method.__name__ = method.__name__        
        return default_abstract_method
    

    http://code.activestate.com/recipes/577666-abstract-method-decorator/

    虽然我没用过。

    【讨论】:

    • 是的.. 好的一点是它将复杂性从抽象类中移出。
    • 是的,这很有趣,我确实在等待这里的讨论时开始使用这种方法。但是,我对另一个答案进行投票,因为适合包含许多其他内容的类定义,使概念实现“更接近”实际需要的地方。
    【解决方案4】:

    请注意,我认为 abc 本身并不能解决我正在寻找的问题。

    实际上abc 正是您要找的。定义一个实现 基类但将其装饰为抽象需要派生类来重新定义它。 当然这有阻止你实例化基类的副作用, 我认为在您的用例中是可以的。

    import abc
    
    
    # inheritance from abc.ABC is important, as otherwise the decorators don't do anything
    class AbstractClass(abc.ABC):
        @abc.abstractmethod
        def amethod(self):
            # some code that should always be executed here
            print("Base implementation")
    
    
    class ActualClass(AbstractClass):
        # will return TypeError: Can't instantiate abstract class ActualClass with abstract methods amethod if not redefined
        def amethod(self):
            # Actual class code
            print("Actual implementation")
    
            # And execute the super class code. (only one super class so less confusing)
            super().amethod()
    
    
    a = ActualClass()
    a.amethod()
    

    【讨论】:

    • 这应该是公认的答案
    【解决方案5】:

    我习惯称之为“填空模式”(注意:这不是设计模式)。您在抽象类中定义一个具体方法,该方法调用抽象方法并用作带有“空白”(抽象方法)的模板。实现抽象方法的子类“填补空白”。在您的简单情况下:

    class AbstractClass(object):
        def amethod(self):
            self._amethod()
            print('Common operations')
    
        @abc.abstractmethod
        def _amethod(self, vars):
            pass
    
    
    class ConcreteClass(AbstractClass):
        def _amethod(self):
            print('Concrete class code')
    

    通常你可以给抽象方法起一个更好的名字。

    【讨论】:

      猜你喜欢
      • 2014-03-18
      • 1970-01-01
      • 2020-02-04
      • 1970-01-01
      • 1970-01-01
      • 2016-12-28
      • 1970-01-01
      • 2020-04-13
      • 1970-01-01
      相关资源
      最近更新 更多