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装饰器
这样就实现了子类的规范化~