Как создать абстрактные свойства в абстрактных классах python
В следующем коде я создаю базовый абстрактный класс Base
. Я хочу, чтобы все классы, наследующие от Base
, предоставляли свойство name
, поэтому я сделал это свойство @abstractmethod
.
Затем я создал подкласс Base
, называемый Base_1
, который предназначен для предоставления некоторых функций, но все равно остается абстрактным. В Base_1
нет свойства name
, но, тем не менее, python инициализирует объект этого класса без ошибки. Как создать абстрактные свойства?
from abc import ABCMeta, abstractmethod
class Base(object):
__metaclass__ = ABCMeta
def __init__(self, strDirConfig):
self.strDirConfig = strDirConfig
@abstractmethod
def _doStuff(self, signals):
pass
@property
@abstractmethod
def name(self):
#this property will be supplied by the inheriting classes
#individually
pass
class Base_1(Base):
__metaclass__ = ABCMeta
# this class does not provide the name property, should raise an error
def __init__(self, strDirConfig):
super(Base_1, self).__init__(strDirConfig)
def _doStuff(self, signals):
print 'Base_1 does stuff'
class C(Base_1):
@property
def name(self):
return 'class C'
if __name__ == '__main__':
b1 = Base_1('abc')
Ответы
Ответ 1
Начиная с Python 3.3 была исправлена ошибка, означающая, что декоратор property()
теперь правильно идентифицируется как абстрактный при применении к абстрактному методу.
Примечание: порядок имеет значение, вы должны использовать @property
до @abstractmethod
Python 3. 3+: (документы по питону):
class C(ABC):
@property
@abstractmethod
def my_abstract_property(self):
...
Python 2: (документы по Python)
class C(ABC):
@abstractproperty
def my_abstract_property(self):
...
Ответ 2
До Python 3.3 вы не можете вложить @abstractmethod
и @property
.
Используйте @abstractproperty
для создания абстрактных свойств (docs).
from abc import ABCMeta, abstractmethod, abstractproperty
class Base(object):
# ...
@abstractproperty
def name(self):
pass
Теперь код вызывает правильное исключение:
Traceback (most recent call last):
File "foo.py", line 36, in
b1 = Base_1('abc')
TypeError: Can't instantiate abstract class Base_1 with abstract methods name
Ответ 3
На основании ответа Джеймса выше
def compatibleabstractproperty(func):
if sys.version_info > (3, 3):
return property(abstractmethod(func))
else:
return abstractproperty(func)
и использовать его в качестве декоратора
@compatibleabstractproperty
def env(self):
raise NotImplementedError()