Python 介面:從協議到抽象基類,python抽象
抽象基類的常見用途:實現介面時作為超類使用。然後,說明抽象基類如何檢查具體子類是否符合介面定義,以及如何使用註冊機制聲明一個類實現了某個介面,而不進行子類化操作。最後,說明如何讓抽象基類自動“識別”任何符合介面的類——不進行子類化或註冊。
Python文化中的介面和協議
介面在動態類型語言中是怎麼運作的呢?首先,基本的事實是,Python語言沒有 interface 關鍵字,而且除了抽象基類,每個類都有介面:類實現或繼承的公開屬性(方法或資料屬性),包括特殊方法,如__getitem__ 或 __add__。
按照定義,受保護的屬性和私人屬性不在介面中:即便“受保護的”屬性也只是採用命名規範實現的(單個前置底線);私人屬性可以輕鬆地訪問,原因也是如此。不要違背這些約定。
另一方面,不要覺得把公開資料屬性放入對象的介面中不妥,因為如果需要,總能實現讀值方法和設值方法,把資料屬性變成特性,使用obj.attr 句法的客戶代碼不會受到影響。 Vector2d 類就是這麼做的,Vector2d 類的第一版,x 和 y 是公開屬性。
vector2d_v0.py:x 和 y 是公開資料屬性
1 class Vector2d:2 3 def __init__(self, x, y):4 self.x = x5 self.y = y6 7 def __iter__(self):8 return (n for n in (self.x, self.y))
我們把 x 和 y 變成了唯讀特性。這是一項重大重構,但是 Vector2d 的介面基本沒變:使用者仍能讀取my_vector.x 和 my_vector.y。
1 class Vector2d: 2 3 def __init__(self, x, y): 4 self.__x = x 5 self.__y = y 6 7 @property 8 def x(self): 9 return self.__x10 11 @property12 def y(self):13 return self.__y14 15 def __iter__(self):16 return (i for i in (self.x, self.y))
Python喜歡序列
Python 資料模型的哲學是盡量支援基本協議。對序列來說,即便是最簡單的實現,Python 也會力求做到最好。
展示了定義為抽象基類的 Sequence 正式介面。
Sequence 抽象基類和 collections.abc 中相關抽象類別的UML 類圖,箭頭由子類指向超類,以斜體顯示的是抽象方法
現在,看看下面