📌 置頂: 請把任何比你弱勢的用路人當作你的至親對待。跟前車保持安全車距 (2秒以上)。

abc — 抽象類別 — 你所不知道的 Python 標準函式庫用法 03

In

,

Tags:



by

abc — Abstract Base Classes

This module provides the infrastructure for defining abstract base classes (ABCs) in Python, as outlined in PEP 3119; see the PEP for why this was added to Python. (See also PEP 3141 and the numbers module regarding a type hierarchy for numbers based on ABCs.)

官方介紹文件:29.7. abc — Abstract Base Classes

01. Quickstart Tutorial

使用 Python abc 套件的原因,是為了要解決 Python 沒有「抽象類別 (abstract class)」的問題。透過抽象類別,我們可以建立一個比起使用 hasattr() 還要更嚴格的類別介面 (class interface) 檢查。

舉例而言,我們來建立一個動物的類別,我們希望之後繼承實作的類別都一定要有「screaming」以及「walk」的方法,我們可以透過 abc.ABCMeta 這個 metaclass 來實作 Animal 抽象類別:

如果不透過 metaclass,我們也可以透過繼承 abc.ABC 這 helper class 達到相同的效果:

當我們使用 Animal 這個抽象類別來建立類別時,就必須要實作 screaming 以及 walk 。如果沒有實作的話,Python 就會產生 TypeError:

我們現在來實作 Dog 這個類別:

我們也可以透過 isinstance 以及 issubclass 檢查 Dog 的類別:

如果有一天,我們認為 Python built-in 的 list 也是一個 Animal,我們可以透過 register 來改變這個事實:

這個用法在 collections.abc 被大量的使用,CPython 在 collections.abc 中定義了許多的基礎抽象類別,例如說 SequenceIterable 等。現實中符合 Sequence 定義的類別有這些:tuplestrrangememoryview。我們可以在原始碼看到,他們被 Sequence register 過:

接著,我們就可以使用 Sequence 這個抽象類別來比較 list 以及 tuple (即使 list 以及 tuple 沒有繼承自 Sequence)。在這邊我們稱作為 virtual subclasses

02. HOW-TO GUIDE

前面提到了抽象方法,那其他的類別屬性也能夠抽象化嗎?答案是可以,自 Python 3.3 版後,只需要在 method decorator 後面加上 abstractmethod 即可:

抽象化 classmethod 以及 staticmethod

抽象化 property

在 class 裡面的 property 也可以要求抽象化,同樣在 decorator 下面加上 abstractmethod 即可:

03. DISCUSSIONS

> abc 的運作原理?

abc.ABCMeta 主要做到三件事情:

  1. ABCMeta 是 metaclass,因此 override __new__ 方法,在這裡面會初始化 abstract 檢查的部分。
  2. override __isinstancecheck__
  3. override __issubclasscheck__

> 如何做到 decorator + abstractmethod 而不需要相對應的 abstract decorator (@abstractclassmethod…etc)?

請參考 commit: bfebb7b54a50f011 以及 bpo-11610

簡而言之,透過新增加 C-API _PyObject_IsAbstract(),在 descrobject 以及 funcobject 的 tp_getset slot 裡面檢查是否有 __isabstractmethod__ 的參數即可。在 object.c 加入了 _PyObject_IsAbstract()、descrobject.c 加入 property_getsetlist、funcobject.c 分別加入 cm_getsetlist 以及 sm_getsetlist 到 tp_getset slot。

> abc.ABC helper class 的運作原理?

abc.ABC 程式碼如下:

大略說明,透過 metaclass=ABCMeta 來繼承 metaclass 的 method,讓普通 class 繼承 ABC 也會有 ABCMeta 的功能。接者把 __slots__ 設為 (),這樣的設定讓其他人無法修改 ABC instance 的 attributes。

有關 __slots__ 的介紹,請參考 __slots__ 以及 使用 __slots__

> get_cache_token 的實際用途?

請參考 functools.py,除了這邊我找不到其他實際用途……

> abc.ABCMeta Performance Issue

請參考下列 mailing list:

abc.ABCMeta 對於 Python startup time 有著嚴重的影響。測出的結果,創立一個 abc.ABCMeta 的 class 會比普通的 class 慢上兩倍以上。同時 abc.ABCMeta 用了三個 weakset,這也是可以改善的地方。

目前上面 mailing list 提出的方法有幾種,一種是把 abc.py 使用 C 改寫、另一種是改善 weakset 的效能,或是改用其他方式。

04. REFERENCE

05. 實際應用

  • fuku-ml – Simple machine learning library / 簡單易用的機器學習套件

Comments

One response to “abc — 抽象類別 — 你所不知道的 Python 標準函式庫用法 03”

  1. […] circular reference、caches 或是需要存放大型物件的地方 (上一篇文章談到的 abc 就有使用 WeakSet 來存放 Class […]

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.