• Python全栈之路系列----之-----面向对象4(接口与抽象,多继承与多态)


    接口类与抽像类

    在python中,并没有接口类这种东西,即便不通过专门的模块定义接口,我们也应该有一些基本的概念

    编程思想 归一化设计:
      1.接口类 不实现具体的方法,并且可以多继承
      2.抽象类 可以做一些基础实现,并且不推荐多继承

    编程的几类原则:

    开放封闭原则:对扩展示开放的,对修改是封闭的
    依赖倒置原则:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该应该依赖细节;细节应该依赖抽象。换言之,要针对接口编程,而不是针对实现编程
    接口隔离原则:使用多个专门的接口,而不使用单一的总接口。即客户端不应该依赖那些不需要的接口。

    接口类

    接口类概念小述:

    接口提取了一群类共同的函数,可以把接口当做一个函数的集合。
    
    然后让子类去实现接口中的函数。
    
    这么做的意义在于归一化,什么叫归一化,就是只要是基于同一个接口实现的类,那么所有的这些类产生的对象在使用时,从用法上来说都一样。
    
    归一化,让使用者无需关心对象的类是什么,只需要的知道这些对象都具备某些功能就可以了,这极大地降低了使用者的使用难度。
    
    比如:我们定义一个动物接口,接口里定义了有跑、吃、呼吸等接口函数,这样老鼠的类去实现了该接口,松鼠的类也去实现了该接口,由二者分别产生一只老鼠和一只松鼠送到你面前,即便是你分别不到底哪只是什么鼠你肯定知道他俩都会跑,都会吃,都能呼吸。
    
    再比如:我们有一个汽车接口,里面定义了汽车所有的功能,然后由本田汽车的类,奥迪汽车的类,大众汽车的类,他们都实现了汽车接口,这样就好办了,大家只需要学会了怎么开汽车,那么无论是本田,还是奥迪,还是大众我们都会开了,开的时候根本无需关心我开的是哪一类车,操作手法(函数调用)都一样
    
    为何要用接口
    概念小述

    接口类:是一种推崇设计模式,增强代码可读性的一种类,他能有效的约束子类代码的编写规范

    from abc import abstractmethod,ABCMeta #导入模块
    # class Payment(metaclass=ABCMeta):      #抽象类/接口类:子类的规范
    #     @abstractmethod                           #装饰器装饰并约束
    #     def payment(self,money):pass     #支付函数,总体负责支付 对应支付的对象和要支付的金额
    class Applepay():
        def payment(self,money):
            print('apple 支付了 %d元'%money)
    class Alipay():
        def payment(self,money):
            print('支付宝 支付了 %d元' % money)
    class Wechatpay():
        def payment(self,money):
            print('微信 支付了 %d元' % money)
    def payment(pay_obj,money):     #归一化设计
        pay_obj.payment(money)
    apple = Applepay()
    ali = Alipay()
    wechat = Wechatpay()
    payment(wechat,100)
    payment(apple,100)
    payment(ali,100)                

    借用abc模块来实现接口

    from abc import ABCMeta,abstractmethod
    
    class Payment(metaclass=ABCMeta):
        @abstractmethod
        def pay(self,money):
            pass
    
    
    class Wechatpay(Payment):
        def fuqian(self,money):
            print('微信支付了%s元'%money)
    
    p = Wechatpay() #不调就报错了

    主动抛异常

      接口初成:手动报异常:NotImplementedError来解决开发中遇到的问题

    class Payment:
        def pay(self):
            raise NotImplementedError
    
    class Wechatpay(Payment):
        def fuqian(self,money):
            print('微信支付了%s元'%money)
    
    
    p = Wechatpay()  #这里不报错
    pay(p,200)      #这里报错了

    抽象类

    什么是抽象类

    抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。

    抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计

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

    为什么要有抽象类

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

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

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

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

    在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
    抽象类

    继承

    多继承问题

      在继承抽象类的过程中,我们应该尽量避免多继承;而在继承接口的时候,我们反而鼓励你来多继承接口

    方法的实现

      在抽象类中,我们可以对一些抽象方法做出基础实现;而在接口类中,任何方法都只是一种规范,具体的功能需要子类实现

    Python的类可以继承多个类,Java和C#中则只能继承一个类

    Python的类如果继承了多个类,那么其寻找方法的方式有两种,分别是:深度优先

    • 当类是经典类时,多继承情况下,会按照深度优先方式查找
    • 当类是新式类时,多继承情况下,会按照广度优先方式查找
    • 经典类和新式类,从字面上可以看出一个老一个新,新的必然包含了跟多的功能,也是之后推荐的写法,从写法上区分的话,如果 当前类或者父类继承了object类,那么该类便是新式类,否则便是经典类。

     代码理解

      1.多继承

    #一般情况下不用
    #接口
    from abc import abstractmethod,ABCMeta
    class Fly_Animal(metaclass=ABCMeta):  #接口类
        @abstractmethod
        def fly(self):pass
    
    class Swim_Animal:
        def swim(self):pass
    
    class Walk_Animal:
        def walk(self):pass
    
    class Tiger(Walk_Animal,Swim_Animal):
        def walk(self):
            print('tiger is walking')
    
    class Frog(Walk_Animal,Swim_Animal):
        def walk(self):
            pass
        def swim(self):
            pass
    
    class Swan(Walk_Animal,Fly_Animal,Swim_Animal):
        def fly(self):
            print('')
        def swim(self):
            pass
        def walk(self):
            pass
    多继承

      2.经典类多继承

    class D:
    
        def bar(self):
            print 'D.bar'
    
    class C(D):
    
        def bar(self):
            print 'C.bar'
    
    class B(D):
    
        def bar(self):
            print 'B.bar'
    
    class A(B, C):
    
        def bar(self):
            print 'A.bar'
    
    a = A()
    # 执行bar方法时
    # 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去D类中找,如果D类中么有,则继续去C类中找,如果还是未找到,则报错
    # 所以,查找顺序:A --> B --> D --> C
    # 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
    a.bar()
    经典类

      3.新式类多继承

    #object 所有类的基类
    #class A(object):  #新式类
         pass
    
    
    class D(object):
    
        def bar(self):
            print 'D.bar'
    
    class C(D):
    
        def bar(self):
            print 'C.bar'
    
    class B(D):
    
        def bar(self):
            print 'B.bar'
    
    class A(B, C):
    
        def bar(self):
            print 'A.bar'
    
    a = A()
    # 执行bar方法时
    # 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错
    # 所以,查找顺序:A --> B --> C --> D
    # 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
    a.bar()
    新式类
    1. 经典类:首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去D类中找,如果D类中么有,则继续去C类中找,如果还是未找到,则报错
    2. 新式类:首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错

    **注意:88在上述查找过程中,一旦找到,则寻找过程立即中断,便不会再继续找

     新式类中查看多继承顺序的关键字:mro()

    a = A()
    a.test()
    print(A.mro())
    

     小结

    class A(object):
        def test(self):
            print('from A')
    
    class B(A):
        def test(self):
            print('from B')
    
    class C(A):
        def test(self):
            print('from C')
    
    class D(B):
        def test(self):
            print('from D')
    
    class E(C):
        def test(self):
            print('from E')
    
    class F(D,E):
        # def test(self):
        #     print('from F')
        pass
    f1=F()
    f1.test()
    print(F.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性
    
    #新式类继承顺序:F->D->B->E->C->A
    #经典类继承顺序:F->D->B->A->E->C
    #python3中统一都是新式类
    #pyhon2中才分新式类与经典类
    
    
    继承原理
    python到底是如何实现继承的,对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表,例如
    
    >>> F.mro() #等同于F.__mro__
    [<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
    
     
    
    为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。
    而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:
    1.子类会先于父类被检查
    2.多个父类会根据它们在列表中的顺序被检查
    3.如果对下一个类存在两个合法的选择,选择第一个父类
    继承小结
    继承的作用
    
    减少代码的重用
    提高代码可读性
    规范编程模式
    
    几个名词
    
    抽象:抽象即抽取类似或者说比较像的部分。是一个从具题到抽象的过程。
    继承:子类继承了父类的方法和属性
    派生:子类在父类方法和属性的基础上产生了新的方法和属性
    
    抽象类与接口类
    复制代码
    
    1.多继承问题
    在继承抽象类的过程中,我们应该尽量避免多继承;
    而在继承接口的时候,我们反而鼓励你来多继承接口
    
    
    2.方法的实现
    在抽象类中,我们可以对一些抽象方法做出基础实现;
    而在接口类中,任何方法都只是一种规范,具体的功能需要子类实现
    
    钻石继承
    
    新式类:广度优先
    经典类:深度优先
    小结
    #继承多态
    
    #新式类和经典类的几个区别 #定义阶段(object) #子类执行父类中的同名方法  #继承问题
    # 抽象类和接口类 归一化设计
        # 编程思想:为子类做规范
        # 归一化设计:几个类都实现了相同的方法
        # 抽象类:最好单继承,且可以简单的实现功能
        # 接口类:可以多继承,且最好不实现具体功能
        # 实现接口类和抽象类的语法
        # from abc import abstractmethod,ABCMeta
        # class 父类(metaclass=ABCMeta):
        #     @abstractmethod
        #     def func(self):pass
    
    # 钻石继承问题
        # python的 新式类 和 经典类 在继承顺序上的不同
        #新式类:广度优先
            #查看继承顺序 子类名.mro()
        #经典类:深度优先   #博大精深
    
    # 多态 python天生支持多态
    
    # 面向对象 继承和组合
    小结2

    多态

    多态指的是一类事物有多种形态

    动物有多种形态:人,狗,猪

    import abc
    class Animal(metaclass=abc.ABCMeta): #同一类事物:动物
        @abc.abstractmethod
        def talk(self):
            pass
    
    class People(Animal): #动物的形态之一:人
        def talk(self):
            print('say hello')
    
    class Dog(Animal): #动物的形态之二:狗
        def talk(self):
            print('say wangwang')
    
    class Pig(Animal): #动物的形态之三:猪
        def talk(self):
            print('say aoao')
    多态

    文件有多种形态:文本文件,可执行文件

    多态

    多态性

    一 什么是多态动态绑定(在继承的背景下使用时,有时也称为多态性)

    多态性是指在不考虑实例类型的情况下使用实例

    在面向对象方法中一般是这样表述多态性:
    向不同的对象发送同一条消息(!!!obj.func():是调用了obj的方法func,又称为向obj发送了一条消息func),不同的对象在接收时会产生不同的行为(即方法)。
    也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。
    
    比如:老师.下课铃响了(),学生.下课铃响了(),老师执行的是下班操作,学生执行的是放学操作,虽然二者消息一样,但是执行的效果不同

    多态性

    peo=People()
    dog=Dog()
    pig=Pig()
    
    #peo、dog、pig都是动物,只要是动物肯定有talk方法
    #于是我们可以不用考虑它们三者的具体是什么类型,而直接使用
    peo.talk()
    dog.talk()
    pig.talk()
    
    #更进一步,我们可以定义一个统一的接口来使用
    def func(obj):
        obj.talk()
    多态

    鸭子类型

    Python崇尚鸭子类型,即‘如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子’
    
    python程序员通常根据这种行为来编写程序。例如,如果想编写现有对象的自定义版本,可以继承该对象
    
    也可以创建一个外观和行为像,但与它无任何关系的全新对象,后者通常用于保存程序组件的松耦合度。
    
    例1:利用标准库中定义的各种‘与文件类似’的对象,尽管这些对象的工作方式像文件,但他们没有继承内置文件对象的方法
    
    例2:序列类型有多种形态:字符串,列表,元组,但他们直接没有直接的继承关系
    
    
    
    #二者都像鸭子,二者看起来都像文件,因而就可以当文件一样去用
    class TxtFile:
        def read(self):
            pass
    
        def write(self):
            pass
    
    class DiskFile:
        def read(self):
            pass
        def write(self):
            pass
  • 相关阅读:
    新概念第二册(1)--英语口语听力课1
    外企面试课程(一)---熟悉常见的缩略词
    公司 邮件 翻译 培训 长难句 结课
    workflow
    公司 邮件 翻译 培训 长难句 20
    公司 邮件 翻译 培训 长难句 19
    Engineering Management
    公司 邮件 翻译 培训 长难句 18
    公司 邮件 翻译 培训 长难句 17
    第14.5节 利用浏览器获取的http信息构造Python网页访问的http请求头
  • 原文地址:https://www.cnblogs.com/zgd1234/p/7552509.html
Copyright © 2020-2023  润新知