第7.21节 Python抽象类—register注册虚拟子类
上两节介绍了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的世界。
欢迎大家批评指正,谢谢大家关注!