如何在Python抽象类中创建抽象属性?

260 投票
7 回答
201896 浏览
提问于 2025-04-16 17:25

在下面的代码中,我创建了一个基础的抽象类 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):
        ...

撰写回答