• 面向对象的三大特性:继承,封装,多态


    一, 什么是面向对象的继承?

    1. 继承是面向对象软件技术当中的一个概念.如果一个类别A'继承自'另一个类别B,就把这个A称作'B的子类别',而把B称为'A的父类别',也可以说'B是A的超类'.继承可以使得子类别具有父类别的各种属性和方法,而不需要再次编写相同的代码.在令子类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类别的原有属性和方法,使其获得与父类别不同的功能.

      # 看一个继承的例子
      class Person:
          def __init__(self, name, sex, age):
              self.name = name
              self.sex = sex
              self.age = age
      class Cat:
          def __init__(self, name, sex, age):
              self.name = name
              self.sex = sex
              self.age = age
      class Dog:
          def __init__(self, name, sex, age):
              self.name = name
              self.sex = sex
              self.age = age
      # 是不是很麻烦,我们来看一下继承
      class Animal:
          def __init__(self, name, sex, age):
              self.name = name
              self.sex = sex
              self.age = age
      class Person(Animal):
          pass
      class Cat(Animal):
          pass
      class Dog(Animal):
          pass
      # Aminal叫做父类,基类,超类
      # Person Cat Dog: 子类,派生类
      
      # 两个类具有相同的功能或者特征的时候. 可以采⽤继承的形式. 提取⼀个⽗类,这个⽗类中编写着两个类相同的部分. 然后两个类分别取继承这个类就可以了
      
    2. 继承的优点显而易见:

      1. 增加了类的耦合性(耦合性不宜多,宜精)
      2. 减少了重复代码
      3. 使得代码更加规范化,合理化

    二, 继承的分类

    1. 补充一下python中类的种类

      1. python 2中存在两种类:
        • 经典类: python 2.2之前一直使用的是经典类,经典类的基类的根什么都不写
        • 新式类: python 2.2之后出现了新式类,新式类的特点是基类的根是object类
      2. 在python 3版本中只有一种类:
        • python 3中使用的都是新式类,如果基类谁都不继承,那这个类会默认继承object
    2. 单继承

      1. 类名,对象执行父类方法

        class Animal(object):
            type_name = '动物类'
            def __init__(self, name, sex, age):
                self.name = name
                self.sex = sex
                self.age = age
            def eat(self):
                print(self)
                print('吃东西')
        
        class Person(Animal):
            pass
        class Cat(Animal):
            pass
        class Dog(Animal):
            pass
        
        # 类名:
        print(Person.type_name) # 可以调用父类的属性,方法
        Person.eat(1)
        ------------------------------------------------
        # 对象:
        # 实例化对象
        p1 = Person('元始天尊', '男', 18)
        print(p1.__dict__)
        # 对象执行类的父类的属性,方法
        print(p1.type_name)
        p1.type_name = '666'
        print(p1.type_name)
        p1.eat()
        
      2. 执行顺序

        # 执行顺序
        class Animal(object):
            type_name = '动物类'
            def __init__(self, name, sex, age):
                self.name = name
                self.sex = sex
                self.age = age
            def eat(self):
                print(self)
                print('吃东西')
        
        class Person(Animal):
            def eat(self):
                print(f'{self.name}吃饭')
        class Cat(Animal):
            pass
        class Dog(Animal):
            pass
        p1 = Person('太上老君', '男', 18)
        # 实例化对象时必须执行__init__方法,类中没有,父类没有,从object类中找
        p1.eat()
        # 先要执行自己类中的eat方法,自己类没有才能执行父类中的方法
        
      3. 同时执行类以及父类的方法

        # 方法一:
        # 如果想执行父类的func方法,这个方法并且子类中也有,那么就在子类的方法中写上: 父类.func(对象,其他参数)
        
        class Animal(object):
            type_name = '动物类'
            def __init__(self, name, sex, age):
                self.name = name
                self.sex = sex
                self.age = age
            def eat(self):
                print(self)
                print('吃东西')
        
        class Person(Animal):
            def __init__(self, name, sex, age, mind):
                Animal.__init__(self, name, sex, age) # 方法一
                self.mind = mind
            def eat(self):
                print(f'{self.name}吃饭')
        class Cat(Animal):
            pass
        class Dog(Animal):
            pass
        
        p1 = Person('孙悟空', '男', 18, '有思想')
        print(p1.__dict__)
        
        -------------------------------------------------
        # 方法二: 利用super,super().func(参数)
        class Animal(object):
            type_name = '动物类'
            def __init__(self, name, sex, age):
                self.name = name
                self.sex = sex
                self.age = age
            def eat(self):
                print(self)
                print('吃东西')
        
        class Person(Animal):
            def __init__(self, name, sex, age, mind):
                # super(Person, self).__init__(name, sex, age) # 方法二
                super().__init__(name, sex, age) # 方法二
                self.mind = mind
            def eat(self):
                print(f'{self.name}吃饭')
        class Cat(Animal):
            pass
        class Dog(Animal):
            pass
        p1 = Person('嫦娥', '女', 18, '有思想')
        print(p1.__dict__)
        
    3. 多继承

      # 例
      class God:
          def __init__(self, name):
              self.name = name
          def fly(self):
              print('会飞')
          def climb(self):
              print('神仙也会爬树')
      class Monkey:
          def __init__(self, sex):
              self.sex = sex
          def climb(self):
              print('会爬树')
      class MonkeySun(God, Monkey): # 多继承
          pass
      sun = MonkeySun('孙悟空')
      sun.climb()
      sun.fly()
      
      1. 经典类的多继承

        # 虽然在python3中已经不存在经典类了,但是经典类的MRO最好还是学一下,这是树形结构遍历的一个最直接的案例,在python的继承体系中,我们可以把类与类继承关系画成一个树形结构的图
        class A:
            pass
        class B(A):
            pass
        class C(A):
            pass
        class D(B, C):
            pass
        class E:
            pass
        class F(D, E):
            pass
        class G(F, D):
            pass
        class H:
            pass
        class Foo(H, G):
            pass
        print(Foo.mro())
        # 查找原则: 在经典类中采用的时深度优先遍历方案,就是一条路走到头,然后再回来,继续找下一个
        

      2. 新式类的多继承: MRO序列

        # MRO是一个有序列表L,在类被创建时就计算出来,计算公式为:
        mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )
        # (其中Child继承自Base1, Base2)
        --------------------------------------------------------------
        # 如果继承至一个基类: class B(A)
        # 这时B的mro序列为
        mro(B) = mro( B (A) )
               = [B] + merge( mro(A) + [A] )
               = [B] + merge( [A] + [A] )
               = [B,A]
        --------------------------------------------------------------
        # 如果继承至多个基类: class B(A1,A2,A3...)
        # 这时B的mro序列
        mro(B) = mro( B(A1,A2,A3...))
               = [B] + merge( mro(A1),mro(A2),mro(A3)...,[A1,A2,A3] )
               = ...
             
        # 计算结果为列表,列表中至少有一个元素,即类自己,如上述示例[A1,A2,A3],merge操作是C3算法的核心
        --------------------------------------------------------------
        # 表头和表尾
        # 表头: 列表的第一个元素
        # 表位: 列表中表头以外的元素集合(可以为空)
        # 示例: 列表[A,B,C] 表头是A,表尾是B和C
        
        # 列表之间的+操作: [A] + [B] = [A,B]
        --------------------------------------------------------------
        # 示例: 计算merge( [E,O], [C,E,F,O], [C] )
        # 1. merge不为空,取出第一个列表[E,O]的表头E,进行判断,各个列表的表尾分别是[O],[E,F,O]
        #    因为E在这些表尾的集合中,因而跳过当前列表
        # 2. 取出第二个列表[C,E,F,O]的表头C,进行判断,各个列表的表尾分别是[O],[E,F,O]
        #    因为C不在这些表尾的集合中,因而将C拿出到merge外,并将所有表头为C的删除
        #    merge( [E,O], [C,E,F,O], [C] ) = [C] + merge( [E,O], [E,F,O])
        # 3. 进行下一次新的merge操作...
        
        

        # mro(A) = mro( A(B,C) )
        # 原式 = [A] + merge( mro(B), mro(C), [B,C] )
        #
        # mro(B) = mro( B(D,E) )
        #        = [B] + merge( mro(D), mro(E), [D,E] ) # 多继承
        #        = [B] + merge( [D,O], [E,O], [D,E] )   # 单继承mro(D(O)) = [D,O]
        #        = [B,D] + merge( [O], [E,O], [E] )     # 拿出并删除D
        #        = [B,D,E] + merge( [O], [O] )          # 拿出并删除E
        #        = [B,D,E,O]
        #
        # mro(C) = mro( C(E,F) )
        #        = [C] + merge( mro(E), mro(F), [E,F] )
        #        = [C] + merge( [E,O], [F,O], [E,F] )
        #        = [C,E] + merge( [O], [F,O], [F] )
        #        = [C,E,F] + merge( [O], [O] )
        #        = [C,E,F,O]
        # 原式 = [A] + merge( [B,D,E,O], [C,E,F,O], [B,C] )
        #      = [A,B] + merge( [D,E,O], [C,E,F,O], [C] )
        #      = [A,B,D] + merge( [E,O], [C,E,F,O], [C] )
        #      = [A,B,D,C] + merge( [E,O], [E,F,O] )
        #      = [A,B,D,C,E] + merge( [O], [F,O] )
        #      = [A,B,D,C,E,F] + merge( [O], [O] )
        #      = [A,B,D,C,E,F,O]
        

    三, 封装

    封装:把一些看似无关紧要的内容组合到一起统一进行存储合使用,这就是封装

    # 封装: 顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容
    # 第一步: 将内容封装到某个地方
    class Foo:
        def __init__(self, name, age):
            self.name = name
            self.age = age
        def detail(self):
            print(self.name)
            print(self.age)
    obj1 = Foo('小红', 18)
    obj2 = Foo('小花', 18)
    # 内容被封装到了对象obj1和obj2中,每个对象中都有name和age属性
    ---------------------------------------------------------
    # 第二步: 从某处调用被封装的内容
    # 通过对象直接调用
    print(obj1.name)
    print(obj2.name)
    # 通过self间接调用被封装的内容
    obj1.detail()
    

    四, 多态,鸭子类型

    • 多态: 同一个对象,多种形态,python默认支持多态

    • 鸭子类型: 你看起来像鸭子,那么你就是鸭子

      class A:
          def f1(self):
              print('in A f1')
          def f2(self):
              print('in A f2')
      class B:
          def f1(self):
              print('in A f1')
          def f2(self):
              print('in A f2')
      # A和B两个类完全没有耦合性,但是在某种意义上他们却统一了一个标准
      # 对相同的功能设定了相同的名字,这样方便开发,这两个方法就可以互称为鸭子类型
      

    五, 类的约束 : 对类的约束

    # 公司让小明给他们的网站完善一个支付功能,小明写了两个类,如下:
    # 版本一
    class QQpay:
        def pay(self, money):
            print(f'使用qq支付{money}元')
    class Alipay:
        def pay(self, money):
            print(f'使用阿里支付{money}元')
    a = Alipay()
    a.pay(100)
    b = QQpay()
    b.pay(200)
    --------------------------------------------------------
    # 但是这样不统一,整改如下:
    # 版本二
    class QQpay:
        def pay(self, money):
            print(f'使用qq支付{money}元')
    class Alipay:
        def pay(self, money):
            print(f'使用阿里支付{money}元')
    
    def pay(obj, money): # 这个函数就是统一支付规则: 归一化设计
        obj.pay(money)
    
    a = Alipay()
    b = QQpay()
    pay(a, 100)
    pay(b, 200)
    -------------------------------------------------------
    # 过了一段时间,换成了新人小马,新加一个微信支付功能
    # 版本三
    class QQpay:
        def pay(self, money):
            print(f'使用qq支付{money}元')
    class Alipay:
        def pay(self, money):
            print(f'使用阿里支付{money}元')
    class Wechatpay:
        def fuqian(self, money):
            print(f'使用微信支付{money}元')
    def pay(obj, money):
        obj.pay(money)
    a = Alipay()
    b = QQpay()
    c = Wechatpay()  # 改变了支付方式,又不统一了
    pay(a, 100)
    pay(b, 200)
    c.fuqian(300)
    ------------------------------------------------------
    # 小马受惩罚,改代码:
    # 版本四
    class QQpay(Payment):
        def pay(self, money):
            print(f'使用qq支付{money}元')
    class Alipay(Payment):
        def pay(self, money):
            print(f'使用阿里支付{money}元')
    class Wechatpay(Payment):
        def pay(self, money):
            print(f'使用微信支付{money}元')
    def pay(obj, money):
        obj.pay(money)
    
    a = Alipay()
    b = QQpay()
    c = Wechatpay()
    pay(a, 100)
    pay(b, 100)
    pay(c, 100)
    # 但是以后再换人还可能出现同样的问题
    -------------------------------------------------------
    # 在一些重要的逻辑,与用户数据相关等核心部分,我们要建立一种约束,避免此种错误
    
    # 所以此时我们要用到对类的约束,对类的约束有两种:
    # 1. 提取父类,然后在父类中定义好方法,在这个方法中什么都不用干,就抛出一个异常就可以了这样所有的子类必须重写这个方法,否则访问的时候就会报错
    # 2. 使用元类来描述父类,在元类中给出一个抽象方法,这样子类就不得不给出抽象方法的具体实现,也可以起到约束的效果(硬性约束)
    -------------------------------------------------------
    # 先用第一种方式解决:
    class Payment:
        def pay(self, money): # 约定俗成定义一种规范,子类要定义pay方法
            raise Exception('你没有实现pay方法')
    class QQpay(Payment):
        def pay(self, money):
            print(f'使用QQ支付{money}元')
    class Alipay(Payment):
        def pay(self, money):
            print(f'使用阿里支付{money}元')
    class Wechatpay(Payment):
        def fuqian(self, money):
            print(f'使用微信支付{money}元')
    def pay(obj, money):
        obj.pay(money)
    a = Alipay()
    b = QQpay()
    c = Wechatpay()
    pay(a, 100)
    pay(b, 200)
    pay(c, 300) # 报错: Exception: 你没有实现pay方法
    # 但是可以绕过
    c.fuqian(300)
    -------------------------------------------------------
    # 第二种方式: 引入抽象类的概念处理
    from abc import ABCMeta
    from abc import abstractmethod
    class Payment(metaclass=ABCMeta): # 抽象类,接口类,规范和约束,metaclass指定的是一个元类
        @abstractmethod
        def pay(self, money): # 抽象方法
            pass
    class QQpay(Payment):
        def pay(self, money):
            print(f'使用QQ支付{money}元')
    class Alipay(Payment):
        def pay(self, money):
            print(f'使用阿里支付{money}元')
    class Wechatpay(Payment):
        def fuqian(self, money):
            print(f'使用微信支付{money}元')
    def pay(obj, money):
        obj.pay(money)
    a = Alipay()
    b = QQpay()
    c = Wechatpay()
    # 报错: TypeError: Can't instantiate abstract class Wechatpay with abstract methods pay
    # 基类如上设置,子类如果没有定义pay方法,在实例化对象时就报错
    pay(a, 100)
    pay(b, 200)
    -------------------------------------------------------
    # 总结: 约束,其实就是父类对子类进行约束,子类必须要写XXX方法,在python中约束的方式和方法有两种
    # 1. 使用抽象类和抽象方法,由于该方案来源是java和C#,所以使用频率还是很少的
    # 2. 使用人为抛出异常的方案,并且尽量抛出的是NotImplementError.这样错误比较明确
    

    六, super()深入了解

    • super是严格按照类的继承顺序执行

    • 单继承: super()肯定是执行父类的方法

    • 多继承: super(S, self) 严格按照self从属于的类的MRO顺序,执行S类的下一类

      class A:
          def f1(self):
              print('in A f1')
          def f2(self):
              print('in A f2')
      class Foo(A):
          def f1(self):
              super().f2()
              print('in A Foo')
      
      obj = Foo()
      obj.f1()
      # in A f2
      # in A Foo
      -----------------------------------------------------
      class A:
          def f1(self):
              print('in A')
      class Foo(A):
          def f1(self):
              super().f1()
              print('in Foo')
      class Bar(A):
          def f1(self):
              print('in Bar')
      class Info(Foo, Bar):
          def f1(self):
              super().f1()
              print('in  Info')
      print(Info.mro()) # Info Foo Bar A  object
      obj = Info()
      obj.f1()
      # in Bar
      # in Foo
      # in  Info
      ----------------------------------------------------
      class A:
          def f1(self):
              print('in A')
      class Foo(A):
          def f1(self):
              super().f1()
              print('in Foo')
      class Bar(A):
          def f1(self):
              print('in Bar')
      class Info(Foo, Bar):
          def f1(self):
              super(Foo, self).f1() # Foo的下个类
              print('in  Info')
      obj = Info()
      obj.f1()
      # in Bar
      # in  Info
      
  • 相关阅读:
    RK3288 Android5.1系统编译
    RK3288 模块单独编译
    ubuntu 设置固定DNS
    PHP取整函数之ceil,floor,round,intval的区别
    PHP实现 APP端微信支付功能
    Laravel中服务提供者和门面模式
    laravel项目利用twemproxy部署redis集群的完整步骤
    PHP转盘抽奖算法
    laravel中短信发送验证码的实现方法
    PHP操作Redis常用
  • 原文地址:https://www.cnblogs.com/zyyhxbs/p/11164293.html
Copyright © 2020-2023  润新知