如何在python中使用abstractproperty decorator强制子类设置属性?

2024-05-08 15:10:27 发布

您现在位置:Python中文网/ 问答频道 /正文

我想强制一个子类来设置几个属性(实例变量),以实现在python2.7中使用abstractproperty decorator。下面是示例代码:

from abc import ABCMeta, abstractproperty
class Parent(object):
    __metaclass__ = ABCMeta
    @abstractproperty
    def name(self):
        pass

class Child1(Parent):
    pass

class Child2(Parent):
    name = 'test'

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

obj_child1 = Child1()

Child1对象创建按预期给出错误。在

^{pr2}$

Child2对象创建工作正常,因为设置了抽象属性'name'

然而

 obj_child3 = Child3()

给出TypeError:无法用抽象方法name实例化抽象类Child3

我没有你理解:尽管属性“name”在init中设置 方法,为什么Child3对象创建引发类型错误。在

我的要求是在子类的方法中设置属性。如果一个child2类中有一个错误的解释可以更好地帮助我在类中使用一个child2的方法来执行。提前谢谢。在


Tags: 对象实例方法nameself属性def错误
3条回答

更简单的解决方案是

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

class Child1(Parent):
    pass

class Child2(Parent):
    name = 'test'

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

obj1 = Child1()引发NotImplementedError

obj2 = Child2()工作正常

obj3 = Child3()工作正常。这就是您需要强制一个子类来设置属性name并从方法中设置属性。在

这就是我认为正在发生的事情。在

当您尝试实例化Child1时,您没有为抽象属性name提供实现。你可能是这样做的:

class Child1(Parent):
    @property
    def name(self):
        return "foo"

由于该类没有为从其父类继承的所有抽象方法提供实现,因此它本身实际上是一个抽象类,因此不能实例化。尝试实例化它会给您TypeError。在

Child2的情况下,将其定义为:

^{pr2}$

在本例中,重写了类的name属性,因此它不再引用需要实现的抽象属性。这意味着Child2不是抽象的,可以实例化。在

我注意到的一个区别是,当name = 'test'实现它时,vars(Child2)返回如下输出:

^{3}$

但是,当您将其更改为foo = 'test'之类的内容时,您将得到:

{..., '__abstractmethods__': frozenset({'name'}), ..., 'foo': 'test'}

请注意,__abstractmethods__属性在您定义name = 'test'的情况下是一个空集,即当Child2可以实例化时。在

最后,在Child3的情况下,您必须记住抽象属性是作为类本身的属性存储的,您不会在任何地方重新定义它。在

一旦您尝试创建它的实例,解释器就会发现它缺少至少一个抽象方法的实现,并抛出您看到的TypeError。它甚至没有到达构造函数中的赋值self.name = 'test'。在


第二部分是关于如何在抽象属性/方法可以像您那样做的时候,如何强制子级始终为抽象属性/方法提供一个实现,我并不确定这是否可能。Python是一种成年人同意的语言。在

你可以这样做, 父类:

class Parent(object):
    __metaclass__ = ABCMeta
    @abstractproperty
   def name(self):
       pass

儿童班:

^{pr2}$

现在

obj = Child() obj.name

提供所需的“test”输出。在

通过这样做,您可以强制一个类来设置父类的属性,而在子类中,您可以从方法中设置它们。 这不是一个完美的解决方案,你需要,但它是接近。这个解决方案的唯一问题是您需要在子类中将父类的所有abstractproperty定义为None,并且它们使用一个方法来设置它们。在

相关问题 更多 >

    热门问题