关于python3.x:Python-abc抽象基类

33次阅读

共计 4484 个字符,预计需要花费 12 分钟才能阅读完成。

该模块提供了在 Python 中定义形象基类(ABC – Abstract Base Class)的根底构造,参考 PEP 3119;至于为何将其增加到 Python,也能够看看PEP 3141numbers模块无关基于 ABC 的数字的类层次结构的模块。

容器 collections 模块具备一些衍生自 ABC 的具体类。当然,这些能够进一步继承衍生。此外,collections.abc子模块具备一些 ABC,可用于测试:类或实例是否提供特定的接口,例如,是否可哈希或是否为映射。

此模块提供 ABCMeta 用于定义 ABC 的元类和帮忙程序类,ABC以通过继承来代替地定义 ABC:

classabc.`ABC

具备 ABCMeta 作为其元类的帮忙程序类。应用此类,能够通过ABC 防止有时混同元数据用法的简略派生来创立形象基类,例如:

from abc import ABC

class MyABC(ABC):
    pass

请留神,类型 ABC 为 still ABCMeta,因而从继承继承 ABC 须要无关元类应用的惯例预防措施,因为多重继承可能会导致元类抵触。也能够通过传递 metaclass 关键字并 ABCMeta 间接应用来定义形象基类,例如:

from abc import ABCMeta

class MyABC(metaclass=ABCMeta):
    pass

3.4 版的新性能。

class abc.`ABCMeta`
用于定义形象基类(ABC)的元类。

应用此元类创立一个 ABC。ABC 能够间接子类化,而后充当混合类。您还能够将不相干的具体类(甚至是内置类)和不相干的 ABC 注册为“虚构子类”–内置 issubclass() 函数会将它们及其后辈视为注册 ABC 的子类,然而注册 ABC 不会显示在其 MRO(办法解决程序)中,由注册 ABC 定义的办法实现也将不可调用(甚至不能通过调用 super())。1 个

应用元类创立的类 ABCMeta 具备以下办法:

register(_subclass_)

将__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__(_子类_)

(必须定义为类办法。)

查看_子类_是否被视为此 ABC 的子类。这意味着您能够自定义 issubclass 进一步的行为,而无需调用 register() 要思考为 ABC 的子类的每个类。(此类办法是从__subclasscheck__()ABC 的办法中调用的。)

这个办法应该返回 TrueFalseNotImplemented。如果返回True,则将该_子类_视为此 ABC 的子类。如果返回False,则即便该子类通常是一个_子类,_也不会将该_子类_视为该 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)

ABC MyIterable将规范可迭代办法定义 __iter__()为形象办法。此处给出的实现仍能够从子类中调用。该 get_iterator() 办法也是 MyIterable 形象基类的一部分,然而在非形象派生类中不用重写此办法~~~~。

__subclasshook__()此处定义的类办法示意,任何 __iter__() 在其类 __dict__(或通过__mro__ 列表拜访的基类之一)中具备办法的 类也被视为类MyIterable

最初,即便没有定义方法,最初一行仍是 Foo 的虚构子类(它应用依照和 定义的新式可迭代协定)。请留神,这不能 作为的办法应用,因而是独自提供的。MyIterable__iter__()__len__()__getitem__()get_iterator`Foo`

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

@`abc.`abstractmethod[](https://docs.python.org/3/lib… “ 此定义的永恒链接 ”)

装璜器,批示形象办法。

应用此装璜器要求该类的元类是 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 形象办法不同,这些形象办法可能具备实现 (Java 新版也有接口默认实现)。能够通过super() 笼罩它的类中的机制来调用此实现。在应用合作式多重继承的框架中,这可用作超级调用的端点。

abc 模块还反对以下新式装璜器:

@`abc.`abstractclassmethod[](https://docs.python.org/3/lib… “ 此定义的永恒链接 ”)

3.2 版中的新性能。

自从 3.3 版本不举荐应用:当初能够应用 classmethodabstractmethod(),使这个装璜是多余的。

内置的子类classmethod(),批示形象的类办法。否则它相似于abstractmethod()

不倡议应用这种非凡状况,因为 classmethod() 当初将装璜器利用于形象办法时,能够正确地将其标识为形象:

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

@`abc.`abstractstaticmethod
3.2 版中的新性能。

自从 3.3 版本不举荐应用:当初能够应用 staticmethodabstractmethod(),使这个装璜是多余的。

内置的子类staticmethod(),批示形象的静态方法。否则它相似于abstractmethod()

不倡议应用这种非凡状况,因为 staticmethod() 当初将装璜器利用于形象办法时,能够正确地将其标识为形象:

class C(ABC):
    @staticmethod
    @abstractmethod
    def my\_abstract\_staticmethod(...):
        ...

@abc.abstractproperty

自从 3.3 版本不举荐应用:当初能够应用 propertyproperty.getter()property.setter()property.deleter()abstractmethod(),使这个装璜是多余的。

内置的子类property(),批示形象属性。

不倡议应用这种非凡状况,因为 property() 当初将装璜器利用于形象办法时,能够正确地将其标识为形象:

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 版的新性能。

脚注

1 个

C++ 程序员应留神,Python 的虚构基类概念与 C ++ 不同。

正文完
 0