abc
— 抽象基類¶
原始碼: Lib/abc.py
此模組為在 Python 中定義抽象基類 (ABC) 提供了基礎架構,如 PEP 3119 中所述;請參閱 PEP 以瞭解為什麼將其新增到 Python 中。(另請參閱 PEP 3141 以及關於基於 ABC 的數字型別層次結構的 numbers
模組。)
collections
模組有一些派生自 ABC 的具體類;當然,這些類可以進一步派生。此外,collections.abc
子模組有一些 ABC,可用於測試類或例項是否提供了特定的介面,例如,它是否是可雜湊的或是否是對映。
此模組提供用於定義 ABC 的元類 ABCMeta
和輔助類 ABC
,以透過繼承來替代定義 ABC
- class abc.ABC¶
一個以
ABCMeta
作為其元類的輔助類。 使用此類,可以透過簡單地從ABC
派生來建立抽象基類,從而避免有時令人困惑的元類用法,例如from abc import ABC class MyABC(ABC): pass
請注意,
ABC
的型別仍然是ABCMeta
,因此,從ABC
繼承需要通常的關於元類用法的預防措施,因為多重繼承可能會導致元類衝突。 也可以透過傳遞 metaclass 關鍵字並直接使用ABCMeta
來定義抽象基類,例如from abc import ABCMeta class MyABC(metaclass=ABCMeta): pass
3.4 版本中新增。
- class abc.ABCMeta¶
用於定義抽象基類 (ABC) 的元類。
使用此元類建立 ABC。 ABC 可以直接子類化,然後充當 mix-in 類。 您還可以將不相關的具體類(甚至是內建類)和不相關的 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__(subclass)¶
(必須定義為類方法。)
檢查 subclass 是否被視為此 ABC 的子類。 這意味著您可以進一步自定義
issubclass()
的行為,而無需對您要視為 ABC 的子類的每個類呼叫register()
。(此類方法是從 ABC 的__subclasscheck__()
方法呼叫的。)此方法應返回
True
、False
或NotImplemented
。 如果它返回True
,則將 subclass 視為此 ABC 的子類。 如果它返回False
,則不會將 subclass 視為此 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__()
類方法表示,任何在其__dict__
(或其基類之一中,透過__mro__
列表訪問)中具有__iter__()
方法的類也被視為MyIterable
。最後,最後一行使
Foo
成為MyIterable
的虛擬子類,即使它沒有定義__iter__()
方法(它使用舊式的可迭代協議,根據__len__()
和__getitem__()
定義)。請注意,這不會使get_iterator
可用作Foo
的方法,因此它是單獨提供的。
abc
模組還提供了以下裝飾器
- @abc.abstractmethod¶
一個指示抽象方法的裝飾器。
使用此裝飾器要求該類的元類是
ABCMeta
或從其派生。 除非覆蓋了所有抽象方法和屬性,否則無法例項化具有從ABCMeta
派生的元類的類。 可以使用任何正常的 'super' 呼叫機制來呼叫抽象方法。abstractmethod()
可以用於宣告屬性和描述符的抽象方法。僅當使用
update_abstractmethods()
函式時,才支援將抽象方法動態新增到類中,或者嘗試修改方法或類一旦建立的抽象狀態。abstractmethod()
僅影響使用常規繼承派生的子類; 不會影響使用 ABC 的register()
方法註冊的“虛擬子類”。當
abstractmethod()
與其他方法描述符結合使用時,它應該作為最內層的裝飾器應用,如下面的用法示例所示:class C(ABC): @abstractmethod def my_abstract_method(self, arg1): ... @classmethod @abstractmethod def my_abstract_classmethod(cls, arg2): ... @staticmethod @abstractmethod def my_abstract_staticmethod(arg3): ... @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()
裝飾器現在被正確地識別為抽象的。class C(ABC): @classmethod @abstractmethod def my_abstract_classmethod(cls, arg): ...
- @abc.abstractstaticmethod¶
3.2 版本新增。
自 3.3 版本起已棄用: 現在可以將
staticmethod
與abstractmethod()
一起使用,這使得此裝飾器變得多餘。內建
staticmethod()
的子類,表示一個抽象靜態方法。其他方面與abstractmethod()
類似。這個特殊情況已被棄用,因為當應用於抽象方法時,
staticmethod()
裝飾器現在被正確地識別為抽象的。class C(ABC): @staticmethod @abstractmethod def my_abstract_staticmethod(arg): ...
- @abc.abstractproperty¶
自 3.3 版本起已棄用: 現在可以將
property
、property.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()¶
返回當前抽象基類快取令牌。
令牌是一個不透明的物件(支援相等性測試),用於標識虛擬子類的抽象基類快取的當前版本。每次在任何 ABC 上呼叫
ABCMeta.register()
時,令牌都會更改。3.4 版本中新增。
- abc.update_abstractmethods(cls)¶
一個重新計算抽象類的抽象狀態的函式。如果一個類的抽象方法在建立後被實現或更改,則應呼叫此函式。通常,應該在類裝飾器中呼叫此函式。
返回 *cls*,以允許用作類裝飾器。
如果 *cls* 不是
ABCMeta
的例項,則不執行任何操作。注意
此函式假定 *cls* 的超類已經更新。它不會更新任何子類。
3.10 版本新增。
腳註