如何在Python抽象类中创建抽象属性?
在下面的代码中,我创建了一个基础的抽象类 Base
。我希望所有从 Base
继承的类都能提供一个 name
属性,所以我把这个属性设置成了 @abstractmethod
。
接着,我创建了一个名为 Base_1
的子类,它是为了提供一些功能,但仍然保持抽象。虽然 Base_1
中没有 name
属性,但 Python 还是能顺利地实例化这个类的对象,没有报错。那么,如何创建抽象属性呢?
from abc import ABCMeta, abstractmethod
class Base(object):
# class Base(metaclass = ABCMeta): <- Python 3
__metaclass__ = ABCMeta
def __init__(self, str_dir_config):
self.str_dir_config = str_dir_config
@abstractmethod
def _do_stuff(self, signals):
pass
@property
@abstractmethod
def name(self):
"""This property will be supplied by the inheriting classes
individually.
"""
pass
class Base1(Base):
__metaclass__ = ABCMeta
"""This class does not provide the name property and should
raise an error.
"""
def __init__(self, str_dir_config):
super(Base1, self).__init__(str_dir_config)
# super().__init__(str_dir_config) <- Python 3
def _do_stuff(self, signals):
print "Base_1 does stuff"
# print("Base_1 does stuff") <- Python 3
class C(Base1):
@property
def name(self):
return "class C"
if __name__ == "__main__":
b1 = Base1("abc")
7 个回答
10
根据上面James的回答
def compatibleabstractproperty(func):
if sys.version_info > (3, 3):
return property(abstractmethod(func))
else:
return abstractproperty(func)
并把它当作一个装饰器来使用
@compatibleabstractproperty
def env(self):
raise NotImplementedError()
58
在 Python 3.3 之前,你不能把 @abstractmethod
和 @property
放在一起使用。
要创建抽象属性,可以使用 @abstractproperty
(文档)。
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
327
从 Python 3.3 开始,修复了一个错误,现在当你把 property()
装饰器用在抽象方法上时,它会被正确识别为抽象的。
注意:顺序很重要,你必须先写 @property
,再写 @abstractmethod
。
Python 3.3及以上版本: (python 文档):
from abc import ABC, abstractmethod
class C(ABC):
@property
@abstractmethod
def my_abstract_property(self):
...
Python 2: (python 文档)
from abc import ABCMeta, abstractproperty
class C:
__metaclass__ = ABCMeta
@abstractproperty
def my_abstract_property(self):
...