在Python中使用带有重写的构造函数的抽象类

问题描述 投票:0回答:1

我正在尝试在Python中将模板方法模式与abc一起使用,以创建可扩展的基类。首先,我需要派生类之一的构造函数来实现从基础构造函数调用的hook方法。本质上,MyBase的所有基类都将具有attr1和attr2,但是只有ChildOne需要验证属性。因此,我不想将初始化移到子类,因为那样会很明显地重复(这里的逻辑很简单,但是在现实世界的应用程序中,显然会变得更加复杂)。这是我在基类中拥有的:

import abc

class MyBase(abc.ABC):
    @abc.abstractmethod
    def __init__(self, attr1, attr2):
        # this is only implemented in one child class
        MyBase.validate_attrs(attr1, attr2)
        self.attr1 = attr1
        self.attr2 = attr2

    @staticmethod
    @abc.abstractmethod
    def validate_attrs(attr1, attr2):
        """ In Child1, raise exception if attr1 or attr2 are invalid """
        pass

我的第一个子类的代码如下:

class ChildOne(MyBase):
    def __init__(self, attr1, attr2, attr3):
        # this class will implement validate_attrs, and logic needs to be called here
        super().__init__(attr1, attr2)
        self.attr3 = attr3

    # Override default from MyBase
    @staticmethod
    def validate_attrs(attr1, attr2):
        if attr1 < attr2:
            raise ValueError("attr1 is too small!")  # this is just stand in logic to keep it brief

但是,当我使用此代码实例化ChildOne时

c1 = ChildOne(1, 2, 3)

默认为pass。我知道这是因为即使1(attr1)小于2(attr2)也不会引发ValueError。我想这是预料之中的,因为我专门叫MyBase.validate_attrs。我尝试使用类方法,但得到相同的结果。从逻辑上讲,似乎我正在尝试从父类中调用子类的逻辑,这显然与任何在OO类中学习过的东西背道而驰。我如何使用模板方法模式通过父类中的hook方法来实现此功能,以便super()在子类中运行已实现的版本?

python-3.x oop design-patterns abstract-class
1个回答
1
投票

使用MyBase.validate_attrs明确表示使用MyBase的版本。但是你不必self将成为实际子类的实例,因此您可以将其更改为:

self.validate_attrs(attr1, attr2)

并且它将调用找到的第一个实现,从实际初始化的子类开始搜索。无需将其设为classmethod,可以直接在实例上调用Python中的staticmethod(装饰器确保即使在实例上调用它们也不会隐式传递selfcls)。

© www.soinside.com 2019 - 2024. All rights reserved.