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

-[ 註解 ]-

[1] C++ 程式設計師需要注意到 Python 中虛擬基底類別的概念和 C++ 中的並
    不相同。
