– 抽象基类 – 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被认为是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))
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 ++的不同. |
评论被关闭。