1. 接口类 VS 抽象类
接口类:python 原生不支持,多继承时使用,且接口类中所有方法均不实现(pass);
抽象类: python原生支持,不支持多继承,抽象类中的方法可以有代码的实现;
接口类和抽象类都是用来规范子类的
先来看一个例子:比如说我们想实现几种方式的支付功能:按照以前学的,完全可以胜任,就是定义类,对类实例化为对象调用里面的方法;
class Wechat(): def pay(self,money): print("使用微信支付%s"%money) class Alipay(): def pay(self,money): print("使用支付宝支付%s"%money) wechat=Wechat() wechat.pay(100) alipay=Alipay() alipay.pay(200)
运行结果:
但其实用户是不关心使用哪种方式去调用的,所以我们可以这样:
class Wechat(): def pay(self,money): print("使用微信支付%s"%money) class Alipay(): def pay(self,money): print("使用支付宝支付%s"%money) def Pay(pay_obj,money): pay_obj.pay(money) wechat=Wechat() # wechat.pay(100) alipay=Alipay() # alipay.pay(200) Pay(wechat,100) Pay(alipay,200)
这有点类似于内置函数,就是我们用户不想管里面复杂的实现,比如计算某一对象的长度L.__len__(),而是最好给我封装成函数,我直接传个参数len(L)
针对上面改造之后的情况,用户调用起来是很方便,但是如果某一天需要另外一个人实现另一个支付功能,比如苹果支付,但是类中用于支付的函数并不是pay,而是别的名字,那直接调用Pay(pay_obj,money)肯定会报错,因为函数Pay(pay_obj,money)中执行pay_obj.pay(money)时肯定会报错的,因为Applepay类中并没有pay这个方法:
class Wechat(): def pay(self,money): print("使用微信支付%s"%money) class Alipay(): def pay(self,money): print("使用支付宝支付%s"%money) class Applepay(): def fuqian(self,money): print("使用苹果支付了%s"%money) def Pay(pay_obj,money): pay_obj.pay(money) wechat=Wechat() # wechat.pay(100) alipay=Alipay() # alipay.pay(200) Pay(wechat,100) Pay(alipay,200) applepay=Applepay() Pay(applepay,300)
运行结果:
针对上面这种情况,其实还可以这样操作:
class Payment(): # 可以让后续写的支付类都需继承这个Payment,当子类去调用pay方法时,如果有的子类中没有实现pay方法(比如Applepay) def pay(self,money): # 当然会来调用父类Payment中的方pay方法,此时就会主动抛一个异常 NotImplemented 表明子类中没有该方法 raise NotImplemented # 主动抛出异常 class Wechat(Payment): def pay(self,money): print("使用微信支付%s"%money) class Alipay(Payment): def pay(self,money): print("使用支付宝支付%s"%money) class Applepay(Payment): def fuqian(self,money): print("使用苹果支付了%s"%money) def Pay(pay_obj,money): pay_obj.pay(money) wechat=Wechat() # wechat.pay(100) alipay=Alipay() # alipay.pay(200) Pay(wechat,100) Pay(alipay,200) applepay=Applepay() Pay(applepay,300)
运行结果:
但是这两种方法,都是必须得去调用Pay(pay_obj,money)方法才行,其实还可以有一种更规范的写法,当实现好一个类时就能发现:
from abc import abstractmethod,ABCMeta class Payment(metaclass=ABCMeta): # 必须指定元类 @abstractmethod # 必须在pay()方法加一个装饰器 def pay(self,money): pass # class Payment(): # 可以让后续写的支付类都需继承这个Payment,当子类去调用pay方法时,如果有的子类中没有实现pay方法(比如Applepay) # def pay(self,money): # 当然会来调用父类Payment中的方pay方法,此时就会主动抛一个异常 NotImplemented 表明子类中没有该方法 # raise NotImplemented # 主动抛出异常 class Wechat(Payment): def pay(self,money): print("使用微信支付%s"%money) class Alipay(Payment): def pay(self,money): print("使用支付宝支付%s"%money) class Applepay(Payment): def fuqian(self,money): print("使用苹果支付了%s"%money) def Pay(pay_obj,money): pay_obj.pay(money) wechat=Wechat() # wechat.pay(100) alipay=Alipay() # alipay.pay(200) # Pay(wechat,100) # Pay(alipay,200) applepay=Applepay() # Pay(applepay,300)
运行结果:
这样只需实例化对象 然后把Pay的功能封装一下,写一个Payment的父类,必须指定元类,以及需要实现在子类共有的需要封装的方法pay()方法,但是需要在该方法之前加上abstractmethod装饰器
这样就实现了子类的规范化~