首页 > 解决方案 > 如何使用父类强制子类为属性设置值?

问题描述

我希望这个Parent类有一个检查机制来确保它的所有子类都为属性设置一个实际值name。我在这里找到了一些东西。

class Parent(object):
    #name = None
    def __init__(self):
        if self.name == None:
            raise NotImplementedError('Subclasses must define name')

class Child1(Parent):
    pass

class Child2(Parent):
    name = 'test'

class Child3(Parent):
    def __init__(self):
        self.name = 'test'

class Child4(Parent):
    def __init__(self):
        pass

#obj1 = Child1() # Expected output: NotImplementedError: Subclasses must define bar

obj2 = Child2()

obj3 = Child3()

obj4 = Child4() # I want the NotImplementedError is raised here as well, but it doesn't

问题是只要__init__子类中有一个方法,它就会覆盖Parent该类并且raise NotImplementedError不再有效。

我目前的工作解决方案是:

class Child5(Parent):
    def __init__(self):
        self.name = 'test'
        super().__init__()

obj5 = Child5() 

这似乎可行,但我想知道它是否是一个正确的实现,或者它是否可能有一些隐藏的陷阱,以及我是否应该学习使用/实现@abstractproperty而不是这个解决方案?

标签: python-3.xinheritanceattributesenforcement

解决方案


在这里,您需要了解何时调用父类构造函数。请注意,在创建子类对象时,如果子类有构造函数,则默认调用它。我们是否也想调用父类构造函数取决于我们,这将由我们完成。但是,如果子类没有构造函数,则调用基类构造函数。

因此,对于您的 Child1(),默认情况下会调用父构造函数,因此会引发异常。

在您的 Child2() 中,也调用了父构造函数。但是请注意,name 变量是静态的,甚至可以作为 Child2.name 访问。因此没有例外。

您的 Child3 类有一个构造函数有一个构造函数,因此永远不会调用父构造函数,因此实际上永远不会检查名称是否存在。因此,您确实需要将以下行添加到子构造函数。

super().__init__()

如果构造函数定义了名称,则应在声明名称后进行此调用。这就是你在 Child5 课堂上所做的。

由于与上述完全相同的原因,Child4 中没有捕获到异常。以下将在 Child4 中检查此情况:

class Child4(Parent):
    def __init__(self):
        super().__init__()

您可以检查构造函数何时被调用,只需在每个构造函数中(最好在开头)添加一个唯一的打印语句(例如 print(1)、print(2) 等)。


推荐阅读