abc
--- 抽象基底類別¶
原始碼:Lib/abc.py
如同在 PEP 3119 中所述,該模組提供了在 Python 中定義抽象基底類別 (ABC) 的基礎元件;若想瞭解為什麼需要在 Python 中增加這個模組,請見 PEP 文件。(也請見 PEP 3141 以及 numbers
模組以瞭解基於 ABC 的數字型別階層關係。)
collections
模块中有一些派生自 ABC 的实体类;当然,这些类还可以进一步被派生。 此外,collections.abc
子模块中有一些可被用于测试一个类或实例是否提供了特定接口的 ABC,例如,它是否为 hashable 或者是否为 mapping 等。
該模組提供了一個用來定義 ABC 的元類別 (metaclass) 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 註冊為「虛擬子類別 (virtual subclass)」 —— 這些類別以及它們的子類別會被內建函式
issubclass()
識別為已註冊 ABC 的子類別,但是該 ABC 不會出現在其 MRO(Method Resolution Order,方法解析順序)中,由該 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()
函数。
你也可以覆寫 (override) 虛擬基底類別中的這個方法:
- __subclasshook__(subclass)¶
(必須定義為類別方法。)
检查 subclass 是否是该 ABC 的子类。 这意味着你可以进一步定制
issubclass()
的行为而无需在每个你希望作为该 ABC 的子类的类上调用register()
。 (这个类方法是在该 ABC 的__subclasscheck__()
方法上被调用的。)该方法应为返回
True
,False
或NotImplemented
。如果返回True
,则 子类 被视为该抽象基类的子类 。如果返回False
,则 子类 不被视为此抽象基类的子类 ,即使它通常是。 如果返回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()
機制來呼叫。這在使用協作多重繼承 (cooperative multiple-inheritance) 的框架中,可以被用作 super 呼叫的一個端點 (end-point)。
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 快取令牌 (cache token)。
此令牌是一個(支援相等性測試的)不透明物件 (opaque object),用於為虛擬子類別標識抽象基底類別快取的當前版本。此令牌會在任何 ABC 上每次呼叫
ABCMeta.register()
時發生更改。在 3.4 版新加入.
- abc.update_abstractmethods(cls)¶
重新計算一個抽象類別之抽象狀態的函式。如果一個類別的抽象方法在建立後被實作或被修改,則應當呼叫此函式。通常此函式應在一個類別裝飾器內部被呼叫。
回傳 cls,使其能夠用作為類別的裝飾器。
如果 cls 不是
ABCMeta
的實例則不做任何操作。備註
此函式會假定 cls 的超類別 (superclass) 已經被更新。它不會更新任何子類別。
在 3.10 版新加入.
註解