[ python ] 接口类和抽象类

接口类

继承有两种用途:
1. 继承基类的方法,并且做出自己的改变或者扩展(代码重用)
2. 申明某个子类兼容于某基类,定义一个接口类interface,接口类定义了一些接口名且未实现接口的功能,子类继承接口类,并且实现接口中的功能

复制代码
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)


ali = Alipay()
pay(ali, 200)
复制代码

 

 

如果我们又定义了一个支付类且没有定义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('已经用Applepay支付%s元.' % money)



def pay(pay_obj, money):
    '''
    支付函数,总体负责支付
    对应支付的对象和要支付的金额
    '''
    pay_obj.pay(money)    # 因为 Applepay 类中未定义 pay 方法


ali = Alipay()
pay(ali, 200)

apple = Applepay()
pay(apple, 300) # 报错
复制代码

 

 

通过上面的例子,报错是因为 Applepay 类中没有定义 pay 方法。在这里我们可以通过继承的关系来手动抛出异常。

复制代码
class Payment:    # 创建一个基类
    def pay(self, money):    # 基类中包含 pay 方法
        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('已经用Applepay支付%s元.' % money)



def pay(pay_obj, money):
    '''
    支付函数,总体负责支付
    对应支付的对象和要支付的金额
    '''
    pay_obj.pay(money)


ali = Alipay()
pay(ali, 200)

apple = Applepay()
pay(apple, 300) # 报错
复制代码

 

 

已知 Applepay 类中没有 pay 方法,则会去基类中寻找,基类中定义的 pay 方法是主动抛出异常。

可以使用 abc 模块来实现接口,自动的去检查是否实现了某方法

复制代码
from abc import ABC, abstractclassmethod, ABCMeta
class Payment(metaclass=ABCMeta):
    @abstractclassmethod
    def pay(self, money):
        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('已经用Applepay支付%s元.' % money)



def pay(pay_obj, money):
    '''
    支付函数,总体负责支付
    对应支付的对象和要支付的金额
    '''
    pay_obj.pay(money)


ali = Alipay()
pay(ali, 200)

apple = Applepay()  # 实例化就能检查出子类是否创建了 pay 方法
复制代码

 

 

实践中,单纯的从子类继承父类的意义不大,甚至有害,因为它使得子类与基类出现强耦合。
继承的第二种含义就非常重要,它又叫‘接口继承’

接口继承实质上是要求‘做出一个良好的抽象,这个抽象规定了一个兼容接口,使得外部调用者无需关心具体细节,可一视同仁的处理,实现了特定接口的所有对象’ -- 这在程序设计上,叫做归一化。

归一化使得高层的外部使用者可以不加区分的处理所有接口兼容的对象集合。

 

抽象类

 

什么是抽象类:

与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化。

为什么要有抽象类:
如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。

比如我们有香蕉的类,有苹果的类,有桃子的类,从这些类抽取相同的内容就是水果这个抽象的类,你吃水果时,
要么是吃一个具体的香蕉,要么是吃一个具体的桃子。。。。。。你永远无法吃到一个叫做水果的东西。

从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。

从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。

从实现角度来看,抽象类与普通类的不同之处在于:抽象类中有抽象方法,该类不能被实例化,只能被继承,且子类必须实现抽象方法。
这一点与接口有点类似,但其实是不同的,即将揭晓答案

 

复制代码
#一切皆文件
import abc #利用abc模块实现抽象类

class All_file(metaclass=abc.ABCMeta):
    all_type='file'
    @abc.abstractmethod #定义抽象方法,无需实现功能
    def read(self):
        '子类必须定义读功能'
        pass

    @abc.abstractmethod #定义抽象方法,无需实现功能
    def write(self):
        '子类必须定义写功能'
        pass

# class Txt(All_file):
#     pass
#
# t1=Txt() #报错,子类没有定义抽象方法

class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法
    def read(self):
        print('文本数据的读取方法')

    def write(self):
        print('文本数据的读取方法')

class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法
    def read(self):
        print('硬盘数据的读取方法')

    def write(self):
        print('硬盘数据的读取方法')

class Process(All_file): #子类继承抽象类,但是必须定义read和write方法
    def read(self):
        print('进程数据的读取方法')

    def write(self):
        print('进程数据的读取方法')

wenbenwenjian=Txt()

yingpanwenjian=Sata()

jinchengwenjian=Process()

#这样大家都是被归一化了,也就是一切皆文件的思想
wenbenwenjian.read()
yingpanwenjian.write()
jinchengwenjian.read()

print(wenbenwenjian.all_type)
print(yingpanwenjian.all_type)
print(jinchengwenjian.all_type)
复制代码

 

 

抽象类与接口类

抽象类的本质还是类,指的是一组类的相似性包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。
抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计
在python中,并没有接口类这种东西,即便不通过专门的模块定义接口,我们也应该有一些基本的概念。

 

本文作者:hukey

本文链接:https://www.cnblogs.com/hukey/p/9889827.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   hukey  阅读(785)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 彩虹 Jay
彩虹 - Jay
00:00 / 00:00
An audio error has occurred.

彩虹 + 轨迹 (Live) - 周杰伦 (Jay Chou)

彩虹

词:周杰伦

曲:周杰伦

哪里有彩虹告诉我

哪里有彩虹告诉我

能不能把我的愿望还给我

能不能把我的愿望还给我

为什么天这么安静

为什么天这么安静

所有的云都跑到我这里

有没有口罩一个给我

有没有口罩一个给我

释怀说了太多就成真不了

释怀说了太多就成真不了

也许时间是一种解药

也许时间是一种解药

也是我现在正服下的毒药

也是我现在正服下的毒药

看不见你的笑 我怎么睡得着

看不见你的笑 我怎么睡得着

你的声音这么近我却抱不到

你的声音这么近我却抱不到

没有地球太阳还是会绕

没有地球太阳还是会绕

没有理由我也能自己走

没有理由我也能自己走

你要离开 我知道很简单

你要离开 我知道很简单

你说依赖 是我们的阻碍

你说依赖 是我们的阻碍

就算放开 但能不能别没收我的爱

就算放开 但能不能别没收我的爱

当作我最后才明白

当作我最后才明白

看不见你的笑 要我怎么睡得着

看不见你的笑 要我怎么睡得着

你的声音这么近我却抱不到

没有地球太阳还是会绕 会绕

没有理由我也能自己走掉

释怀说了太多就成真不了

也许时间是一种解药 解药

也是我现在正服下的毒药

轨迹

词:黄俊郎

曲:周杰伦

我会发着呆然后忘记你

接着紧紧闭上眼

想着哪一天 会有人代替

想着哪一天 会有人代替

让我不再想念你

我会发着呆 然后微微笑

我会发着呆 然后微微笑

接着紧紧闭上眼

又想了一遍 你温柔的脸

又想了一遍 你温柔的脸

在我忘记之前