在下面的代码中,我创建了一个抽象基类Base
。我希望从Base
继承的所有类都提供name
属性,所以我将此属性设置为@abstractmethod
。
然后我创建了Base
的一个子类,叫做Base_1
,它的目的是提供一些功能,但仍然保持抽象。在Base_1
中没有name
属性,但python却在没有错误的情况下instatinate了该类的一个对象。如何创建抽象属性呢?
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')
6条答案
按热度按时间u7up0aaq1#
例如,您可以在**
Person
抽象类**中定义@abstractmethod
和@property
、@name.setter
或@name.deleter
的抽象getter、setter和deleter,如下所示。*@abstractmethod
必须是最里面的装饰器,否则会出错:然后用**
Student
类扩展Person
抽象类**,覆盖**Student
类中抽象得getter、setter、deleter,示例化Student
类**,调用getter、setter、deleter,如下图:输出量:
实际上,即使您不覆盖**
Student
类中的抽象setter和deleter,也可以示例化Student
类**,如下所示:未发生错误,如下所示:
但是,如果您不覆盖**
Student
类中的抽象getter、setter和deleter,并示例化Student
类**,如下所示:出现以下错误:
TypeError:无法使用抽象方法名称示例化抽象类Student
而且,如果您不覆盖**
Student
类中的抽象getter并示例化Student
类**,如下所示:出现以下错误:
NameError:未定义名称'name'
并且,如果
@abstractmethod
不是最里面的装饰器,如下所示:出现以下错误:
属性错误:“property”对象的特性“isabstractmethod”不可写
gstyhher2#
从Python 3.3开始,一个bug被修复了,这意味着当
property()
装饰器被应用于一个抽象方法时,它现在被正确地标识为抽象。注意:顺序很重要,您必须使用
@property
以上的@abstractmethod
Python 3.3以上版本:(Python文档):
Python 2:(Python文档)
oo7oh9g93#
在Python 3.3之前,你不能嵌套
@abstractmethod
和@property
。使用
@abstractproperty
创建抽象属性(docs)。程式码现在会引发正确的例外状况:
dnph8jn44#
根据James的上述回答
把它当作装饰品
wdebmtf25#
如果您希望所需的示例级属性也使用属性装饰器,则可以在抽象类中使用
@property
装饰器(如answer by James中所建议的)。如果你不想使用属性装饰器,你可以使用
super()
。我最终使用了类似于dataclasses的__post_init__()
,它获得了示例级属性所需的功能:vc9ivgsu6#
在python 3.6+中,你也可以在不提供默认值的情况下对变量进行注解,我发现这是一种更简洁的方法来使其抽象化。
它还可以用于强制您初始化
__new__
或__init__
方法中的变量作为另一个示例,当您尝试初始化
Base_1
类时,以下代码将失败AttributeError: 'Base_1' object has no attribute 'name'