仅在特定情况下才具有特定属性的强制性属性/变量

时间:2018-07-10 12:58:01

标签: python python-3.x

我有一个具有“强制”属性的抽象类:

class PMixin(ABC):

    @property
    @abstractmethod
    def progressbar_step(self):
        raise NotImplementedError

仅在特定情况下才可能具有强制属性,而并非在所有子条款中都具有强制属性。

我使用多重继承,所以如果是A类

class A(PMixin, B)

B的继承也不是强制性的,否则是强制性的。

如果不是B的子类,则A从PMixin继承所有。

如果它也继承自B,则不需要progressbar_step。

我可以在progressbar_step=None中声明:PMixin 并仅在不继承自B的情况下才覆盖它,并解决问题,例如

class PMixin(ABC):
  progressbar_step = None

class A(PMixin)
  progressbar_step = 5

class A2(PMixin, B)
 ....

但是我想得到一个警告,在什么情况下有一个值,在示例A中; 这只是一种编码“安全”机制

2 个答案:

答案 0 :(得分:1)

这是使用__init__subclass__的解决方案,在Python 3.6中可用。每当PMixin被子类化时都会调用此方法,我们可以使用它从满足我们条件的子类中删除abstractmethod

from abc import ABC, abstractmethod

class B:
    pass

class PMixin(ABC):
    @property
    @abstractmethod
    def progressbar_step(self):
        raise NotImplementedError
    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        if issubclass(cls, B):
            print('is subclass')
            print(cls.progressbar_step)
            cls.progressbar_step = None

class A(PMixin):  # Will raise error
        pass

class C(PMixin, B):  # No error
    pass

如果您希望在子类PMixin时发出警告,而不是尝试实例化该子类的对象,则可以在cls.progressbar_step.__isabstractmethod__中检查__init_subclass__并适当地发出警告。

答案 1 :(得分:0)

对于<3.6的python版本,您可以为PMixin定义一个自定义元类:

class PMixinMeta(type):
    def __new__(mcs, names, bases, body):
        klass = super().__new__(mcs, names, bases, body)
        if issubclass(klass, B):  # 'if B in bases' is also ok 
            klass.progressbar_step = None
        return klass

但是,由于ABC也使用自定义元类,因此,如果将PMixinMeta定义为PMixin的元并继承自ABC,则会遇到元类冲突。 / p>

因此您需要创建一个中间元类来解决冲突。

from abc import ABCMeta

class PMixinAbcMeta(ABCMeta, PMixinMeta):
    pass

,然后将PMixinAbcMeta定义为PMixin的元类

from abc import abstractmethod

class PMixin():
    __metaclass__ = PMixinAbcMeta
    @property
    @abstractmethod
    def progressbar_step(self):
        raise NotImplementedError

注意:只有启动(使用__init__的{​​{1}}子类的实例后,您才会获得异常。

如果您希望在构建期间收到异常,PMixin应该看起来像这样:

PMixinMeta

意味着现在:

class PMixinMeta(type):
    def __new__(mcs, names, bases, body):
        klass = super().__new__(mcs, names, bases, body)
        if issubclass(klass, B):
            klass.progressbar_step = None
        else:
            if 'progressbar_step' not in body:
                raise ValueError('must have a progressbar_step method')
        return klass

不仅会引发异常,还会引发异常:

class A(PMixin):
    pass
相关问题