abc
abc - 抽象基类
2.6版本中的新功能。
源代码:
Lib / abc.py
该模块提供了用Python 定义抽象基类(ABCs)的基础结构,如PEP 3119所述
; 请参阅PEP为什么将其添加到Python。(另请参阅PEP 3141
和numbers
基于ABCs的关于数字类型层次的模块。)
该collections
模块有一些来自ABCs的具体类; 当然,这些可以进一步推导出来。此外,该collections
模块还有一些可用于测试类或实例是否提供特定接口的ABCs,例如,它是可散列还是映射。
该模块提供以下类:
class abc.ABCMeta
用于定义抽象基类(ABC)的元类。
使用这个元类来创建一个ABC。ABC可以直接分类,然后作为混合课。您也可以将不相关的具体类(甚至内置类)和不相关的ABCs注册为“虚拟子类” - 这些及其后代将被内置issubclass()
函数视为注册ABC的子类,但注册ABC不会显示(方法解析顺序),注册ABC定义的方法实现也不会被调用(甚至不能super()
)。[1]
使用元类创建的类ABCMeta
具有以下方法:
register(subclass)
将子类
注册为此ABC的“虚拟子类”。例如:
from abc import ABCMeta
class MyABC:
__metaclass__ = ABCMeta
MyABC.register(tuple)
assert issubclass(tuple, MyABC)
assert isinstance((), MyABC)
您也可以在抽象基类中重写此方法:
__subclasshook__(subclass)
(必须定义为类方法。)
检查子类
是否被认为是该ABC的一个子类。这意味着您可以自定义issubclass
进一步的行为,而无需调用register()
您想考虑ABC的子类的每个类。(这个类的方法是从__subclasscheck__()
ABC 的方法中调用的。)
此方法应返回True,False或NotImplemented。 如果它返回True,则该子类被认为是该ABC的一个子类。 如果返回False,则该子类不被视为该ABC的子类,即使它通常是一个。 如果它返回NotImplemented,则子类检查将继续使用通常的机制。
为了演示这些概念,请看这个ABC定义的例子:
class Foo(object):
def __getitem__(self, index):
...
def __len__(self):
...
def get_iterator(self):
return iter(self)
class MyIterable:
__metaclass__ = ABCMeta
@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)
ABC MyIterable
将标准迭代方法定义__iter__()
为抽象方法。这里给出的实现仍然可以从子类中调用。该get_iterator()
方法也是MyIterable
抽象基类的一部分,但它不必在非抽象派生类中重写。
这里定义的__subclasshook __()类方法表示,任何在其__dict__(或其基类之一,通过__mro__列表访问)中具有__iter __()方法的类也被视为MyIterable。
最后,最后一行使Foo成为MyIterable的虚拟子类,即使它没有定义__iter __()方法(它使用旧式可迭代协议,用__len __()和__getitem __())定义。 请注意,这不会使get_iterator作为Foo的方法提供,因此它是单独提供的。
它还提供了以下装饰器:
abc.abstractmethod(function)
指示抽象方法的装饰器。
使用这个装饰器需要该类的元类是ABCMeta或从它派生。 除非所有抽象方法和属性都被覆盖,否则不能实例化具有派生自ABCMeta的元类的类。 抽象方法可以使用任何普通的“超级”调用机制来调用。
不支持动态地将抽象方法添加到类中,或者尝试在创建方法或类时修改抽象状态。将abstractmethod()
仅影响使用常规继承派生的子类; 用ABC register()
方法注册的“虚拟子类” 不受影响。
用法:
class C:
__metaclass__ = ABCMeta
@abstractmethod
def my_abstract_method(self, ...):
...
注意
与Java抽象方法不同,这些抽象方法可能有一个实现。这个实现可以通过super()
覆盖它的类的机制来调用。这可以作为使用协作多重继承的框架中的超级调用的终点。
abc.abstractproperty([fget[, fset[, fdel[, doc]]]])
内置的子类property()
,表示抽象属性。
使用这个函数需要该类的元类是ABCMeta或从它派生。 除非所有抽象方法和属性都被覆盖,否则不能实例化具有派生自ABCMeta的元类的类。 抽象属性可以使用任何普通的“超级”调用机制来调用。
用法:
class C:
__metaclass__ = ABCMeta
@abstractproperty
def my_abstract_property(self):
...
这定义了一个只读属性; 你也可以使用'long'属性声明来定义一个读写抽象属性:
class C:
__metaclass__ = ABCMeta
def getx(self): ...
def setx(self, value): ...
x = abstractproperty(getx, setx)
脚注
1 | C ++程序员应该注意到Python的虚拟基类概念与C ++不同。 |
---|