簡介:
python中雖然鴨子型別很強大,但鴨子型別也有著不足。具體關於分類可以參照水禽的分類理解。
因此,參照水禽的分類學演化,我建議在鴨子型別的基礎上增加白鵝型別(goose typing)。白鵝型別指,只要cls
是抽象基類,即cls
的元類是abc.abcmeta
,就可以使用isinstance(obj, cls)
collections.abc
中有很多有用的抽象類(python 標準庫的numbers
模組中還有一些)。
與具體類相比,抽象基類有很多理論上的優點(例如,參閱 scott meyer 寫的《more effective c++:35 個改善程式設計與設計的有效方法(中文版)》的「條款 33:將非尾端類設計為抽象類」,英文版見 的抽象基類還有乙個重要的實用優勢:可以使用register
類方法在終端使用者的**中把某個類「宣告
」為乙個抽象基類的「虛擬
」子類(為此,被註冊的類必須滿足抽象基類對方法名稱和簽名的要求,最重要的是要滿足底層語義契約;但是,開發那個類時不用了解抽象基類,更不用繼承抽象基類)。
這大大地打破了嚴格的強耦合,與物件導向程式設計人員掌握的知識有很大出入,因此使用繼承時要小心。
有時,為了讓抽象基類識別子類,甚至不用註冊。
其實,抽象基類的本質就是幾個特殊方法。例如:
可以看出,無需註冊,abc.sized
也能把a
識別為自己的子類,只要實現了特殊方法__len__
即可。(要使用正確的句法和語義實現,前者要求沒有引數,後者要求返回乙個非負整數,指明物件的長度;如果不使用規定的句法和語義實現特殊方法,如__len__
,會導致非常嚴重的問題)。
最後我想說的是:如果實現的類體現了numbers、collections.abc
或其他框架中抽象基類
的概念,要麼繼承相應的抽象基類
(必要時),要麼把類註冊到相應的抽象基類中
。開始開發程式時,不要使用提供註冊功能的庫或框架,要自己動手註冊;如果必須檢查引數的型別(這是最常見的),例如檢查是不是「序列」,那就這樣做:
isinstance(the_arg, collections.abc.sequence)
此外,不要在生產**中定義抽象基類(或元類)……如果你很想這樣做,我打賭可能是因為你想「找茬」,剛拿到新工具的人都有大幹一場的衝動。如果你能避開這些深奧的概念,你(以及未來的**維護者)的生活將更愉快,因為**會變得簡潔明瞭。
除了提出「白鵝型別」
之外,alex 還指出,繼承抽象基類很簡單,只需要實現所需的方法,這樣也能明確表明開發者的意圖。這一意圖還能通過註冊虛擬子類來實現。
此外,使用isinstance
和issubclass
測試抽象基類更為人接受。過去,這兩個函式用來測試鴨子型別,但用於抽象基類會更靈活。畢竟,如果某個元件沒有繼承抽象基類,事後還可以註冊,讓顯式型別檢查通過。
然而,即便是抽象基類,也不能濫用isinstance
檢查,用得多了可能導致**異味,即表明物件導向設計得不好。在一連串if/elif/elif
中使用isinstance
做檢查,然後根據物件的型別執行不同的操作,通常是不好的做法;此時應該使用多型
,即採用一定的方式定義類,讓直譯器把呼叫分派給正確的方法,而不使用if/elif/elif
塊硬編碼分派邏輯。(具體使用時,上述建議有乙個常見的例外:有些 python api 接受乙個字串或字串序列;如果只有乙個字串,可以把它放到列表中,從而簡化處理。因為字串是序列型別,所以為了把它和其他不可變序列區分開,最簡單的方式是使用isinstance(x, str)
檢查。)
另一方面,如果必須強制執行 api 契約,通常可以使用isinstance
檢查抽象基類。「老兄,如果你想呼叫我,必須實現這個」,正如本書技術審校 lennart regebro 所說的。這對採用插入式架構的系統來說特別有用。在框架之外,鴨子型別通常比型別檢查更簡單,也更靈活。
注意:抽象基類是用於封裝框架引入的一般性概念和抽象的,例如「乙個序列」和「乙個確切的數」。(讀者)基本上不需要自己編寫新的抽象基類,只要正確使用現有的抽象基類,就能獲得 99.9% 的好處,而不用冒著設計不當導致的巨大風險。
下一次來說明抽象基類的繼承和定義自己的抽象基類。
python抽象基類理解
抽象基類它提供了介面,但是又沒有去把介面實現的類,需要由子類完成。感覺它就是老闆,只告訴你要完成專案a,你接到專案a後 繼承 你自己去把它完成。抽象基類特點 1.繼承類必須實現抽象基類的方法 2.抽象基類無法例項化 1.why 抽象基類?譬如要開發乙個專案,你要規定專案開發者要去完成某些介面,有些介...
python3 抽象基類
1,抽象基類 abstract base class或者 abcs 用於 定義一組必須被類的 鴨子型別 例項實現的方法與屬性,可以繼承抽象基類本身的類作為類的例項,但是必須提供所有適合的方法。from collections.abc import container class testcontai...
ACM 抽象基類
檔名稱 完成日期 2014年6月3日 版本號 v0.1 對任務及求解方法的描述部分 輸入描述 無 問題描述 程式輸入 程式輸出 問題分析 演算法設計 我的程式 include include using namespace std class shape class circle public sh...