26. abc

abc 模块提供了在 Python 中定义抽象基类(abstract base classes)的组件。

26.1. 抽象基类

抽象基类可以通过从 ABC 派生来简单地创建,

1from abc import ABC
2
3class MyABC(ABC):
4    pass

也可以直接使用 ABCMeta 作为元类(metaclass)来定义抽象基类,

1from abc import ABCMeta
2
3class MyABC(metaclass=ABCMeta):
4    pass

26.2. 抽象方法

@abc.abstractmethod 是用于声明抽象方法的装饰器。

抽象方法与继承:

  • 继承一个没有抽象方法的抽象类,不需要重写(override)抽象方法也能实例化。

  • 继承有抽象方法的抽象类但没有重写抽象方法会报错,子类重写抽象方法不需要 abstractmethod 修饰。

  • 继承有抽象方法的非抽象类不会报错。

abstractmethod 与其他方法描述符配合使用时,它应当作为最内层的装饰器。

 1class C(ABC):
 2    @abstractmethod
 3    def my_abstract_method(self):
 4        pass
 5    @classmethod
 6    @abstractmethod
 7    def my_abstract_classmethod(cls):
 8        pass
 9    @staticmethod
10    @abstractmethod
11    def my_abstract_staticmethod():
12        pass
13
14    @property
15    @abstractmethod
16    def my_abstract_property(self):
17        pass
18    @my_abstract_property.setter
19    @abstractmethod
20    def my_abstract_property(self, val):
21        pass
22
23    @abstractmethod
24    def _get_x(self):
25        ...
26    @abstractmethod
27    def _set_x(self, val):
28        ...
29    x = property(_get_x, _set_x)

26.3. 虚子类

register(subclass) 将子类注册为该抽象基类的虚子类(virtual subclass)。 issubclassisinstance 等函数都能识别,但是该抽象基类不会出现在其 MRO(Method Resolution Order,方法解析顺序)中,虚子类并不会从抽象基类中继承任何方法,也无需重写抽象方法。虚子类是为类型检测准备的,由于不需要重写抽象方法,因此第三方接口的可扩展性和灵活性更高。

1from abc import ABC
2
3class MyABC(ABC):
4    pass
5
6MyABC.register(tuple)
7
8assert issubclass(tuple, MyABC)
9assert isinstance((), MyABC)

内建属性 __mro__ 按顺序列出当前类及其祖先类, __subclasses__() 列出子孙类。

 1from abc import *
 2class A(metaclass=ABCMeta):
 3    @abstractmethod
 4    def func1(self):
 5        pass
 6
 7@A.register
 8class B:
 9    def func2(self):
10        pass
11## 等价于 A.register(B)
12
13
14class C(A):
15    def func1(self):
16        pass
1>>> c = C()
2>>> print(C.__mro__)
3(<class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
4>>> print(A.__subclasses__())
5[<class '__main__.C'>]

26.4. 参考资料

  1. abc — Abstract Base Classes

  1. python之抽象类&abc模块+虚拟子类&register

  1. 协议与接口与抽象基类