抽象基類的常見用途:實(shí)現(xiàn)接口時(shí)作為超類使用。然后,說明抽象基類如何檢查具體子類是否符合接口定義,以及如何使用注冊機(jī)制聲明一個(gè)類實(shí)現(xiàn)了某個(gè)接口,而不進(jìn)行子類化操作。最后,說明如何讓抽象基類自動(dòng)“識(shí)別”任何符合接口的類——不進(jìn)行子類化或注冊。
Python文化中的接口和協(xié)議
接口在動(dòng)態(tài)類型語言中是怎么運(yùn)作的呢?首先,基本的事實(shí)是,Python語言沒有 interface 關(guān)鍵字,而且除了抽象基類,每個(gè)類都有接口:類實(shí)現(xiàn)或繼承的公開屬性(方法或數(shù)據(jù)屬性),包括特殊方法,如__getitem__ 或 __add__。
按照定義,受保護(hù)的屬性和私有屬性不在接口中:即便“受保護(hù)的”屬性也只是采用命名約定實(shí)現(xiàn)的(單個(gè)前導(dǎo)下劃線);私有屬性可以輕松地訪問,原因也是如此。不要違背這些約定。
另一方面,不要覺得把公開數(shù)據(jù)屬性放入對象的接口中不妥,因?yàn)槿绻枰偰軐?shí)現(xiàn)讀值方法和設(shè)值方法,把數(shù)據(jù)屬性變成特性,使用obj.attr 句法的客戶代碼不會(huì)受到影響。 Vector2d 類就是這么做的,Vector2d 類的第一版,x 和 y 是公開屬性。
vector2d_v0.py:x 和 y 是公開數(shù)據(jù)屬性
class Vector2d: def __init__(self, x, y): self.x = x self.y = y def __iter__(self): return (n for n in (self.x, self.y))
我們把 x 和 y 變成了只讀特性。這是一項(xiàng)重大重構(gòu),但是 Vector2d 的接口基本沒變:用戶仍能讀取my_vector.x 和 my_vector.y。
class Vector2d: def __init__(self, x, y): self.__x = x self.__y = y @property def x(self): return self.__x @property def y(self): return self.__y def __iter__(self): return (i for i in (self.x, self.y))
Python喜歡序列
Python 數(shù)據(jù)模型的哲學(xué)是盡量支持基本協(xié)議。對序列來說,即便是最簡單的實(shí)現(xiàn),Python 也會(huì)力求做到最好。
下圖展示了定義為抽象基類的 Sequence 正式接口。

Sequence 抽象基類和 collections.abc 中相關(guān)抽象類的UML 類圖,箭頭由子類指向超類,以斜體顯示的是抽象方法
現(xiàn)在,看看下面
新聞熱點(diǎn)
疑難解答
圖片精選