abc --- 抽象基底類別

原始碼:Lib/abc.py


如同在 PEP 3119 中所述,該模組提供了在 Python 中定義抽象基底類別 (ABC) 的基礎元件;若想瞭解為什麼需要在 Python 中增加這個模組,請見 PEP 文件。(也請見 PEP 3141 以及 numbers 模組以瞭解基於 ABC 的數字型別階層關係。)

The collections module has some concrete classes that derive from ABCs; these can, of course, be further derived. In addition, the collections.abc submodule has some ABCs that can be used to test whether a class or instance provides a particular interface, for example, if it is hashable or if it is a mapping.

該模組提供了一個用來定義 ABC 的元類別 (metaclass) ABCMeta 和另一個以繼承的方式定義 ABC 的工具類別 ABC

class abc.ABC

A helper class that has ABCMeta as its metaclass. With this class, an abstract base class can be created by simply deriving from ABC avoiding sometimes confusing metaclass usage, for example:

from abc import ABC

class MyABC(ABC):
    pass

Note that the type of ABC is still ABCMeta, therefore inheriting from ABC requires the usual precautions regarding metaclass usage, as multiple inheritance may lead to metaclass conflicts. One may also define an abstract base class by passing the metaclass keyword and using ABCMeta directly, for example:

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]

Classes created with a metaclass of ABCMeta have the following method:

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 版的變更: To detect calls to register(), you can use the get_cache_token() function.

你也可以覆寫 (override) 虛擬基底類別中的這個方法:

__subclasshook__(subclass)

(必須定義為類別方法。)

Check whether subclass is considered a subclass of this ABC. This means that you can customize the behavior of issubclass() further without the need to call register() on every class you want to consider a subclass of the ABC. (This class method is called from the __subclasscheck__() method of the ABC.)

This method should return True, False or NotImplemented. If it returns True, the subclass is considered a subclass of this ABC. If it returns False, the subclass is not considered a subclass of this ABC, even if it would normally be one. If it returns NotImplemented, the subclass check is continued with the usual mechanism.

為了對這些概念做一演示,請見以下定義 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)

The ABC MyIterable defines the standard iterable method, __iter__(), as an abstract method. The implementation given here can still be called from subclasses. The get_iterator() method is also part of the MyIterable abstract base class, but it does not have to be overridden in non-abstract derived classes.

這裡定義的 __subclasshook__() 類別方法說明任何在其 __dict__ (或在其透過 __mro__ 列表訪問的基底類別) 中具有 __iter__() 方法的類別也都會被視為 MyIterable

Finally, the last line makes Foo a virtual subclass of MyIterable, even though it does not define an __iter__() method (it uses the old-style iterable protocol, defined in terms of __len__() and __getitem__()). Note that this will not make get_iterator available as a method of Foo, so it is provided separately.

The abc module also provides the following decorator:

@abc.abstractmethod

用於表示抽象方法的裝飾器。

Using this decorator requires that the class's metaclass is ABCMeta or is derived from it. A class that has a metaclass derived from ABCMeta cannot be instantiated unless all of its abstract methods and properties are overridden. The abstract methods can be called using any of the normal 'super' call mechanisms. abstractmethod() may be used to declare abstract methods for properties and descriptors.

Dynamically adding abstract methods to a class, or attempting to modify the abstraction status of a method or class once it is created, are only supported using the update_abstractmethods() function. The abstractmethod() only affects subclasses derived using regular inheritance; "virtual subclasses" registered with the ABC's register() method are not affected.

When abstractmethod() is applied in combination with other method descriptors, it should be applied as the innermost decorator, as shown in the following usage examples:

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)

In order to correctly interoperate with the abstract base class machinery, the descriptor must identify itself as abstract using __isabstractmethod__. In general, this attribute should be True if any of the methods used to compose the descriptor are abstract. For example, Python's built-in property does the equivalent of:

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)。

The abc module also supports the following legacy decorators:

@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 版之後被棄用: 現在可以讓 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):
        ...

The abc module also provides the following functions:

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 版新加入.

註解