abc抽象基础类

源代码:LIB / abc.py


该模块提供了定义抽象基础Python中的(ABC),如PEP 3119 ;请参阅PEP,了解为何将其添加到Python中。(另见 PEP 3141 numbers关于基于ABCs的数字类型层次的模块。)

collections模块有一些来自ABC的具体类;当然,这些可以进一步推导出来。除此之外collections.abc子模块有一些可用于测试whethera类或实例提供特定接口的ABC,例如,如果它是可用的或者是映射的话

这个模块提供了元类ABCMeta来定义ABCs和一个帮助类ABC来通过继承来定义ABCs:

class abc.ABC

一个有ABCMeta作为其元类。使用这个类,可以通过简单地从ABC派生来创建抽象基类,避免有时混淆元类使用,例如:

from abc import ABCclass MyABC(ABC):    pass

注意ABC还是 ABCMeta因此,请从进行ABC需要关于元类使用的常规预防措施,因为多重继承可能导致元类冲突。也可以通过传递元类关键字并使用ABCMeta直接,例如:

from abc import ABCMetaclass MyABC(metaclass=ABCMeta):    pass

版本3.4.

class abc.ABCMeta

中的新类,用于定义抽象基类(ABC).

使用此元类创建ABC。ABC可以直接子类化,然后作为混合类。你也可以注册不相关的具体类(甚至是内置类)和不相关的ABCs作为“虚拟子类” – 这些和它们的后代将被内置的issubclass()函数,但注册ABC不会出现在他们的MRO(方法解析顺序)中,注册ABC定义的methinmplementation也不会被调用(甚至不能通过super())。[1]

使用ABCMeta元类创建的类具有以下方法:

registersubclass

注册subclass作为ABC的“虚拟子类”。例如:

from abc import ABCclass MyABC(ABC):    passMyABC.register(tuple)assert issubclass(tuple, MyABC)assert isinstance((), MyABC)

在版本3.3中更改:返回已注册的子类,以允许用作类装饰器.

更改版本3.4:检测register()的调用,你可以使用get_cache_token()函数

你也可以在抽象基类中覆盖这个方法:

__subclasshook__subclass

(必须定义为类方法。)

检查subclass是否被视为此ABC的子类。这意味着您可以进一步自定义issubclass的行为,而无需在要考虑作为ABC的子类的每个类上调用register()。(这个类方法是从ABC的__subclasscheck__()方法调用的。)

这个方法应该返回True, FalseNotImplemented。if if返回Truesubclass被认为是这个ABC的子类。如果它返回Falsesubclass不被认为是这个ABC的子类,甚至如果它通常是一个。如果它返回NotImplemented,继续使用normalmechanism.

有关这些概念的演示,请查看此示例ABC定义:

class Foo:    def __getitem__(self, index):        ...    def __len__(self):        ...    def get_iterator(self):        return iter(self)class MyIterable(ABC):    @abstractmethod    def __iter__(self):        while False:            yield None    def get_iterator(self):        return self.__iter__()    @classmethod    def __subclasshook__(cls, C):        if cls is MyIterable:            if any("__iter__" in B.__dict__ for B in C.__mro__):                return True        return NotImplementedMyIterable.register(Foo)

ABC MyIterable将标准可迭代方法__iter__()定义为抽象方法。给定的实现仍然可以从子类调用。get_iterator()方法也是MyIterable抽象基类的一部分,但它不必在非抽象派生类中重写.

__subclasshook__()类这里定义的方法说任何在__iter__()(或者它的一个基类中,__dict__列表中访问)中有__mro__方法的clas被认为是MyIterable too.

最后,最后一行使Foo成为MyIterable的虚拟子类,即使它没有定义__iter__()方法(它使用旧式的可迭代协议,用__len__()__getitem__()来定义。请注意,这不会使get_iterator作为Foo的方法可用,所以它是单独提供的.

abc模块还提供以下装饰器:

@abc.abstractmethod

指示抽象方法的装饰者

使用这个装饰器要求类的元类ABCMeta或者是从它派生的。除非所有抽象方法和属性都被覆盖,否则无法实例化具有从ABCMeta派生的元类的类。可以使用任何普通的“超级”调用机制来调用抽象方法。abstractmethod()可用于声明属性和描述符的抽象方法.

不支持动态地向类添加抽象方法,或者尝试在创建方法或类时修改其抽象状态。abstractmethod()只影响使用常规继承派生的子类;用ABC的register()方法注册的“虚拟子类”不受影响.

abstractmethod()与其他方法描述符结合使用时,它应该被用作最里面的装饰器,如在以下用法示例中显示:

class C(ABC):    @abstractmethod    def my_abstract_method(self, ...):        ...    @classmethod    @abstractmethod    def my_abstract_classmethod(cls, ...):        ...    @staticmethod    @abstractmethod    def my_abstract_staticmethod(...):        ...    @property    @abstractmethod    def my_abstract_property(self):        ...    @my_abstract_property.setter    @abstractmethod    def my_abstract_property(self, val):        ...    @abstractmethod    def _get_x(self):        ...    @abstractmethod    def _set_x(self, val):        ...    x = property(_get_x, _set_x)

为了正确地与抽象基类机制进行互操作,描述符必须使用__isabstractmethod__。一般来说,这个属性应该是True如果用于组成描述符的任何方法都是抽象的。例如,Python的内置property相当于:

class Descriptor:    ...    @property    def __isabstractmethod__(self):        return any(getattr(f, "__isabstractmethod__", False) for                   f in (self._fget, self._fset, self._fdel))

注意

与Java抽象方法不同,这些抽象方法可能有一个实现。这个实现可以通过super()来自覆盖它的类的机制。在使用协同多重继承的框架中,这可以作为asuper-call的终点.

abc模块还支持以下传统装饰器:

@abc.abstractclassmethod

版本3.2.

从版本3.3开始不推荐使用:现在可以使用classmethodabstractmethod(),使这个装饰多余.

内置的classmethod()子类,表示abstractclass方法。否则它类似于abstractmethod().

这个特殊情况已被弃用,如classmethod()当应用于abstractmethod时,decorator现在被正确识别为抽象

class C(ABC):    @classmethod    @abstractmethod    def my_abstract_classmethod(cls, ...):        ...
@abc.abstractstaticmethod

版本3.2.

从版本3.3开始不推荐使用:现在可以使用staticmethodabstractmethod(),使这个装饰器变得多余.

内置的staticmethod()子类,表示一个抽象的静态方法。否则它类似于abstractmethod().

这个特殊情况已被弃用,因为staticmethod() decorator现在在应用于abstractmethod时正确地标识为抽象

class C(ABC):    @staticmethod    @abstractmethod    def my_abstract_staticmethod(...):        ...
@abc.abstractproperty

自版本3.3以后不推荐使用:现在可以使用property, property.getter(),property.setter()property.deleter()abstractmethod(),使这个装饰器多余了

内置的子类property(),表示一个abstractproperty。

这个特殊情况已被弃用,因为property() decorator现在在应用于abstractmethod时正确地被识别为抽象

class C(ABC):    @property    @abstractmethod    def my_abstract_property(self):        ...

以上example定义了一个只读属性;您还可以通过将一个或多个基本方法适当地标记为abstract来定义aread-write抽象属性:

class C(ABC):    @property    def x(self):        ...    @x.setter    @abstractmethod    def x(self, val):        ...

如果只有一些组件是抽象的,那么只需要更新那些组件以在子类中创建具体属性:

class D(C):    @C.x.setter    def x(self, val):        ...

abc模块还提供以下功能:

abc.get_cache_token

返回当前的抽象基类缓存标记.

标记是一个不透明的对象(即支持等式测试)识别虚拟子类抽象基类缓存的当前版本。令牌随着对任何ABC的ABCMeta.register()的调用而改变.

版本3.4.

Footnotes

[1] C ++程序员应该注意到Python的虚拟基类概念与C ++的不同.

评论被关闭。