– 抽象基类 – Python运行时服务(Python教程)(参考资料)
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可以直接子类化,然后作为混合类。你也可以注册不相关的具体类(甚至是内置类)和不相关的ABCs作为“虚拟子类” – 这些和它们的后代将被内置的
issubclass()函数,但注册ABC不会出现在他们的MRO(方法解析顺序)中,注册ABC定义的methinmplementation也不会被调用(甚至不能通过super())。[1]register(subclass)-
注册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,False或NotImplemented。if if返回True,subclass被认为是这个ABC的子类。如果它返回False,subclass不被认为是这个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被认为是MyIterabletoo.最后,最后一行使
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))
abc模块还支持以下传统装饰器:
@abc.abstractclassmethod-
版本3.2.
从版本3.3开始不推荐使用:现在可以使用
classmethod与abstractmethod(),使这个装饰多余.内置的
classmethod()的子类,表示abstractclass方法。否则它类似于abstractmethod().这个特殊情况已被弃用,如
classmethod()当应用于abstractmethod时,decorator现在被正确识别为抽象:class C(ABC): @classmethod @abstractmethod def my_abstract_classmethod(cls, ...): ...
@abc.abstractstaticmethod-
版本3.2.
从版本3.3开始不推荐使用:现在可以使用
staticmethod和abstractmethod(),使这个装饰器变得多余.内置的
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 ++的不同. |
评论被关闭。