上兩節介紹了Python抽象類的真實子類的定義和使用,本節介紹另一種抽象類的實現方法:虛擬子類方法。
一、 相關概念
虛擬子類是將其他的不是從抽象基類派生的類”注冊“到抽象基類,讓Python解釋器將該類作為抽象基類的子類使用,因此稱為虛擬子類,這樣第三方類不需要直接繼承自抽象基類。注冊的虛擬子類不論是否實現抽象基類中的抽象內容,Python都認為它是抽象基類的子類,調用 issubclass(子類,抽象基類),isinstance (子類對象,抽象基類)都會返回True。
這種通過注冊增加虛擬子類是抽象基類動態性的體現,也是符合Python風格的方式。它允許我們動態地,清晰地改變類的屬別關系。當一個類繼承自抽象基類時,該類必須完成抽象基類定義的語義;當一個類注冊為虛擬子類時,這種限制則不再有約束力,可以由程序開發人員自己約束自己,因此提供了更好的靈活性與擴展性(當然也帶來了一些意外的問題)。這種能力在框架程序使用第三方插件時,采用虛擬子類即可以明晰接口,只要第三方插件能夠提供框架程序要求的接口,不管其類型是什么,都可以使用抽象基類去調用相關能力,又不會影響框架程序去兼容外部接口的內部實現。老猿認為,從某種程度上講,虛擬子類這種模式,是在繼承這種模式下的一種多態實現。
二、 語法
1. 虛擬子類定義的前面步驟都與真實子類相同,首先都是import abc 模塊,然后定義抽象基類;
2. 定義子類;
3. 將子類注冊為抽象基類的虛擬子類,語法為:
基類名. register(子類名)三、 例子說明
1、 以上節的Shape類為例,定義抽象基類
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def getArea():pass #定義獲取面積的抽象方法
@abstractmethod
def getGirth():pass #定義獲取周長的抽象方法
2、 定義非Shape派生類
class House():
def __init__(self,area):self.area=area
def showArea(self):return self.area
3、 將House類注冊為Shape的子類
Shape.register(House)
4、 定義House類實例化變量
house=House(100)
5、 查看House類是否為Shape子類,實例house是否為Shape的實例
issubclass(House,Shape)
isinstance(house,Shape)
四、 執行代碼及截圖
#coding:utf-8
#抽象類虛擬子類
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def getArea():pass #定義獲取面積的抽象方法
class House():
def __init__(self,area):self.area=area
def showArea(self):return self.area
Shape.register(House)
issubclass(House,Shape)
house=House(100)
isinstance(house,Shape)
house.getArea()#執行報錯,沒有該方法
class House():#調整類定義,將showArea方法改成getArea
def __init__(self,area):self.area=area
def getArea(self):return self.area
issubclass(House,Shape)#由於類重新定義,該函數應該返回False
Shape.register(House)#重新注冊虛擬子類
house=House(100)#重新定義變量:
issubclass(House,Shape)
isinstance(house,Shape)

本節結合案例詳細介紹了通過子類注冊到抽象基類的方式實現虛擬子類的方法,注冊虛擬子類無需子類實現抽象基類的所有抽象方法,在某些特定場景下非常有用。
老猿Python(https://blog.csdn.net/LaoYuanPython)系列文章用於逐步介紹老猿學習Python后總結的學習經驗,這些經驗有助於沒有接觸過Python的程序員可以很容易地進入Python的世界。
歡迎大家批評指正,謝謝大家關注!
