我有一个具有“强制”属性的抽象类:
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中; 这只是一种编码“安全”机制
答案 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