abc ---抽象基类¶
源代码: Lib/abc.py
此模块提供用于定义 abstract base classes (abcs)在python中,如 PEP 3119 ;请参阅PEP了解为什么将此添加到Python中。(也见) PEP 3141 以及 numbers 关于基于abcs的数字类型层次结构的模块。)
这个 collections 模块具有一些从ABC派生的具体类;当然,这些类可以进一步派生。此外, collections.abc 子模块有一些abc,可以用来测试一个类或实例是否提供了一个特定的接口,例如,它是可散列的还是映射的。
此模块提供元类 ABCMeta 用于定义ABC和助手类 ABC 或者通过继承来定义ABC:
- class abc.ABC¶
具有
ABCMeta作为它的元类。使用这个类,可以通过简单地从ABC避免有时混淆元类用法,例如:from abc import ABC class MyABC(ABC): pass
注意
ABC仍然是ABCMeta因此继承自ABC需要有关元类使用的常规预防措施,因为多个继承可能导致元类冲突。还可以通过传递元类关键字并使用ABCMeta直接,例如:from abc import ABCMeta class MyABC(metaclass=ABCMeta): pass
3.4 新版功能.
- class abc.ABCMeta¶
用于定义抽象基类(abcs)的元类。
使用此元类创建ABC。ABC可以直接子类化,然后作为类中的混合。您还可以将不相关的具体类(甚至内置类)和不相关的ABC注册为“虚拟子类”——这些子类及其后代将被内置的ABC注册子类视为
issubclass()函数,但是注册ABC不会显示在它们的MRO(方法解析顺序)中,注册ABC定义的方法实现也不会被调用(即使通过super()) 1用的元类创建的类
ABCMeta方法如下:- register(subclass)¶
寄存器 子类 作为本ABC的“虚拟子类”。例如::
from abc import ABC class MyABC(ABC): pass MyABC.register(tuple) assert issubclass(tuple, MyABC) assert isinstance((), MyABC)
在 3.3 版更改: 返回已注册的子类,以允许用作类修饰器。
在 3.4 版更改: 检测对的调用
register(),您可以使用get_cache_token()功能。
还可以在抽象基类中重写此方法:
- __subclasshook__(subclass)¶
(必须定义为类方法。)
检查是否 子类 被认为是ABC的一个子类。这意味着您可以自定义
issubclass更进一步,无需调用register()对于每一个类,您都要考虑ABC的一个子类。(此类方法是从__subclasscheck__()ABC方法。)此方法应返回
True,False或NotImplemented. 如果它回来True, the 子类 被认为是ABC的一个子类。如果它回来False, the 子类 不被认为是ABC的一个子类,即使它通常是ABC的一个子类。如果它回来NotImplemented,子类检查继续使用常规机制。
有关这些概念的演示,请看下面的示例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 NotImplemented MyIterable.register(Foo)
抽象基类
MyIterable定义标准ITerable方法,__iter__(),作为抽象方法。这里给出的实现仍然可以从子类中调用。这个get_iterator()方法也是MyIterable抽象基类,但不必在非抽象派生类中重写它。这个
__subclasshook__()这里定义的类方法表示任何具有__iter__()方法在其__dict__(或在它的一个基类中,通过__mro__列表)被视为MyIterable也是。最后,最后一行
Foo的虚拟子类MyIterable,即使它没有定义__iter__()方法(它使用了旧式的ITerable协议,根据__len__()和__getitem__())注意这不会使get_iterator可用作Foo,因此它是单独提供的。
这个 abc 模块还提供以下装饰:
- @abc.abstractmethod¶
指示抽象方法的修饰符。
使用此修饰符要求类的元类是
ABCMeta或者是从中衍生出来的。具有派生自的元类的类ABCMeta除非重写其所有抽象方法和属性,否则无法实例化。抽象方法可以使用任何普通的“超级”调用机制来调用。abstractmethod()可用于声明属性和描述符的抽象方法。仅支持将抽象方法动态添加到类中,或者在创建方法或类后尝试修改其抽象状态。
update_abstractmethods()功能。这个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()重写它的类的机制。这对于使用合作多继承的框架中的超级调用来说是有用的。
这个 abc 模块还支持以下遗留装饰器:
- @abc.abstractclassmethod¶
3.2 新版功能.
3.3 版后已移除: 现在可以使用
classmethod具有abstractmethod()使这个装饰器成为多余的。内置的子类
classmethod(),指示抽象类方法。否则类似于abstractmethod().此特殊情况已弃用,因为
classmethod()当应用于抽象方法时,decorator现在正确地标识为abstract::class C(ABC): @classmethod @abstractmethod def my_abstract_classmethod(cls, ...): ...
- @abc.abstractstaticmethod¶
3.2 新版功能.
3.3 版后已移除: 现在可以使用
staticmethod具有abstractmethod()使这个装饰器成为多余的。内置的子类
staticmethod(),指示抽象静态方法。否则类似于abstractmethod().此特殊情况已弃用,因为
staticmethod()当应用于抽象方法时,decorator现在正确地标识为abstract::class C(ABC): @staticmethod @abstractmethod def my_abstract_staticmethod(...): ...
- @abc.abstractproperty¶
3.3 版后已移除: 现在可以使用
property,property.getter(),property.setter()和property.deleter()具有abstractmethod()使这个装饰器成为多余的。内置的子类
property(),指示抽象属性。此特殊情况已弃用,因为
property()当应用于抽象方法时,decorator现在正确地标识为abstract::class C(ABC): @property @abstractmethod def my_abstract_property(self): ...
上面的示例定义了只读属性;您还可以通过将一个或多个基础方法适当标记为抽象来定义读写抽象属性::
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()¶
返回当前抽象基类缓存令牌。
令牌是一个不透明的对象(支持相等性测试),用于标识虚拟子类的抽象基类缓存的当前版本。每次调用时令牌都会更改
ABCMeta.register()在任何ABC上。3.4 新版功能.
- abc.update_abstractmethods(cls)¶
重新计算抽象类的抽象状态的函数。如果类的抽象方法在创建后已实现或更改,则应调用此函数。通常,应该从类修饰器内部调用此函数。
退货 cls ,以允许用作类装饰器。
如果 cls 不是
ABCMeta,什么也不做。注解
此函数假定 cls 的超类已经更新。它不更新任何子类。
3.10 新版功能.
脚注
- 1
C++程序员应该注意到Python的虚拟基类概念与C++的不一样。