Python abc—抽象基類

該模塊提供了在Python中定義抽象基類(ABC - Abstract Base Class)的基礎結構,參考PEP 3119;至於爲什麼將其添加到 Python,也能夠看看PEP 3141numbers模塊有關基於ABC的 numbers 的類層次結構的模塊。html

容器collections模塊具備一些衍生自ABC的具體類。固然,這些能夠進一步繼承衍生。此外, collections.abc子模塊具備一些 ABC,可用於測試:類或實例是否提供特定的接口,例如,是否可哈希或是否爲映射。python

此模塊提供ABCMeta用於定義ABC 的元類和幫助程序類,ABC以經過繼承來替代地定義ABC:程序員

classabc.`ABC緩存

具備ABCMeta做爲其元類的幫助程序類。使用此類,能夠經過ABC 避免有時混淆元數據用法的簡單派生來建立抽象基類,例如:框架

from abc import ABC

class MyABC(ABC):
    pass

請注意,類型ABC爲still ABCMeta,所以從繼承繼承ABC須要有關元類使用的常規預防措施,由於多重繼承可能會致使元類衝突。也能夠經過傳遞 metaclass 關鍵字並ABCMeta直接使用來定義抽象基類,例如:ssh

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個code

使用元類建立的類ABCMeta具備如下方法:htm

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++不一樣。

相關文章
相關標籤/搜索