【问题标题】:Can a parent's class method call an abstract method which will be implemented in a child class?父类方法可以调用将在子类中实现的抽象方法吗?
【发布时间】:2020-08-06 02:38:25
【问题描述】:

如果我的父类有两种方法:

class Parent():
    @abstractmethod
    @staticmethod
    def functionA():
       pass
    
    def functionB():
       return __class__.functionA() + 1

我实现了一个子类:

class Child(Parent):
    def functionA(): # this function is different for each kind of child
        return 3

最后,子类的目的是只调用functionB()。 它有效吗?当然,我可以把functionB()放到子类中让它工作,但是因为functionB()对于每种子类都是一样的,我不想为每个类写重复的代码?

另外,我在这里使用__class__ 合适吗?

【问题讨论】:

  • 为什么不将functionB定义为@classmethod,并返回不同的父类实例?

标签: python class inheritance abstract


【解决方案1】:

首先,functionB 本身应该是一个类方法。

@classmethod
def functionB(cls):
    return cls.functionA() + 1

其次,你还是要把functionA装饰成每个子类中的静态方法;否则,您将用实例方法替换继承的静态方法。

class Child(Parent):

    @staticmethod
    def functionA():
        return 3

【讨论】:

    【解决方案2】:

    这是一个工作版本:

    from abc import ABC, abstractmethod
    
    class Parent(ABC):
        @staticmethod # not needed, but is documentation
        @abstractmethod
        def a(): pass
    
        @classmethod
        def b(cls): return cls.a() + 1
    
    class Child(Parent):
        @staticmethod
        def a(): return 3
    

    我们可以测试一下:

    >>> c = Child()
    >>> c.b()
    4
    

    值得注意的事情:

    • 我们需要使用ABC 基类(或ABCMeta 元类)才能访问abstractmethod 装饰器,如abc 模块文档中所述。

    • __class__ 不是关键字;它是一个对象的属性。我们不能只做__class__.a() 之类的事情,因为没有什么可以得到__class__ 来自。我们可以使用普通方法的self 参数来解决这个问题,但我们在这里真正想要做的是获得不需要实例但取决于哪个实例的行为我们正在使用的派生类。这就是 classmethod 的用途,以及为什么有单独的 classmethodstaticmethod 装饰器。

    当您使用classmethod 时,该类将作为参数传递,就像您使用普通方法时如何传递实例一样。按照惯例,我们将其命名为cls。有关classmethod的更多信息,请参阅this excellent talk by Raymond Hettinger (on the Python dev team)

    • 我们对抽象方法的实现也必须在子类中进行装饰,因为它们仍然不是普通的方法 - 所以 Python 需要知道不要传递实例。

    • 出于技术原因,抽象方法上的staticmethod 装饰需要首先列出,在abstractmethod 装饰之前。它在这里实际上什么都不做。 abstractmethod 的行为已经像 staticmethod 当我们调用例如Parent.a()(没有实例;无论如何我们都无法创建实例,因为它是一个抽象类)。

    • 对于a 方法,我们也可以使用classmethod 而不是staticmethod。这将允许Child 的子代继承Child 行为,而无需明确编写自己的a 实现。在这种情况下,我们希望在基本抽象方法上显式地装饰classmethod,而不是staticmethod;当然,我们需要为每个a 实现添加cls 参数。

    【讨论】:

    • 谢谢,看来使用classmethod 是去这里的方式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-28
    • 2021-08-08
    • 1970-01-01
    相关资源
    最近更新 更多