zoukankan      html  css  js  c++  java
  • 面向对象 继承 (inheritance)

    面向对象 继承 (inheritance)

    面向对象的继承

    继承定义

    • 继承(英语:inheritance)是面向对象软件技术当中的一个概念 / 一种创建新类的方式
    • B类 继承 A类 , B类 叫做 A类的 子类 / 派生类 , A类 叫做 B类 的父类 / 基类 / 超类
    • B类以及B类的对象 使用A类的所有的属性及方法

    优点

    1. 增加了类的耦合性(耦合性不宜多,宜精)/ 耦合性太高是缺点
    2. 减少了重复代码 / 节省代码
    3. 使得代码更加规范化,合理化 / 规范化代码
    4. 重写父类代码 / 覆盖父类代码
    class Person:
        def __init__(self,name,sex,age):
            self.name = name
            self.age = age
            self.sex = sex
    
    class Cat:
        def __init__(self,name,sex,age):
            self.name = name
            self.age = age
            self.sex = sex
    
    class Dog:
        def __init__(self,name,sex,age):
            self.name = name
            self.age = age
            self.sex = sex
    
    # 继承的用法:
    class Aniaml(object):  # Aminal 叫做父类 / 基类 / 超类(对于下面的子类来说)
                           # object 是Animal的父类
        def __init__(self,name,sex,age):
                self.name = name
                self.age = age
                self.sex = sex
    
    
    class Person(Aniaml):  # Person Cat Dog  子类 / 派生类
        pass
    
    class Cat(Aniaml):
        pass
    
    class Dog(Aniaml):
        pass
    

    继承的分类

    分类 : 单继承 / 多继承

    单继承

    子类 执行 / 调用 父类 的方法

    对象 执行 父类 的一切 ***

    • 注意: 子类以及子类对象只能调用父类的属性以及方法,不能操作(增删改).
    # 类名,对象分别调用父类方法
    class Aniaml(object): #  Aminal 叫做父类 / 基类 / 超类
        type_name = '动物类'
    
        def __init__(self,name,sex,age):
                self.name = name
                self.age = age
                self.sex = sex
    
        def eat(self):
            print(self)
            print('吃东西')
    
    
    class Person(Aniaml): # 子类 / 派生类  下面这三个都是属于子类调用父类
        pass
    
    
    class Cat(Aniaml):  # 子类 / 派生类
        pass
    
    
    class Dog(Aniaml):  # 子类 / 派生类
        pass
    
    # 子类 执行 (调用) 父类 的 属性 / 方法: 
    print(Person.type_name)  # 可以调用父类的属性,方法。
    Person.eat(111)
    print(Person.type_name)
    
    # 对象:
    # 实例化对象
    p1 = Person('春哥','男',18)
    print(p1.__dict__)
    # 对象执行类的父类的属性,方法。
    print(p1.type_name)
    p1.type_name = '666'
    print(p1)
    p1.eat()
    # 注意: 子类以及子类对象只能调用父类的属性以及方法,不能操作(增删改).
    
    

    执行顺序

    class Aniaml(object):
        type_name = '动物类'
        def __init__(self,name,sex,age):
                self.name = name
                self.age = age
                self.sex = sex
    
        def eat(self):
            print(self)
            print('吃东西')
    
    class Person(Aniaml):
        
        def eat(self):   # 子类将父类的方法覆盖了,(重写父类的方法)
            print('%s 吃饭'%self.name)
            
    class Cat(Aniaml):
        pass
    
    class Dog(Aniaml):
        pass
    
    p1 = Person('barry','男',18)
    # 实例化对象时必须执行__init__方法,类中没有,从父类找,父类没有,从object类中找。
    p1.eat()
    # 先要执行自己类中的eat方法,自己类没有才能执行父类中的方法。
    

    实例化对象时必须执行__init__方法, 本类中没有,从父类找,父类没有,从object类中找

    先要执行自己类中的方法,自己类没有才能执行父类中的方法。

    同时执行类及父类方法

    方法一

    • 如果想执行父类的func方法,这个方法并且子类中也用,那么就在子类的方法中写上:
      父类.func(对象,其他参数)

    方法二

    • 利用super,super().func(参数)
    class Animal:
        
        def __init__(self,name,age,gender):
            self.name = name
            self.age = age
            self.gender = gender
            
        def eat(self):
            print("动物都需要进食")
            
    class Person(Animal):
        
        def __init__(self,name,age,gender,hobby):
            # 方法一
            Animal.__init__(self,name,age,gender)
            # 方法二
            super().__init__(name,age,gender)  # 相当于super(Person, self).__init__(name, age, sex)
        def eat(self):
            print("人类需要吃饭")
            super().eat()
            
    p1 = Person('怼怼哥', 23, '不详','吹牛逼') 
    p1.eat() 
    # "人类需要吃饭"
    # "动物都需要进食"
    

    多继承

    class God: # 神仙
        def fei(self):
            print("神仙都会⻜")
    class Monkey: # 猴
        def chitao(self):
            print("猴⼦喜欢吃桃⼦")
    class SunWukong(God, Monkey): # 孙悟空是神仙, 同时也是⼀只猴  即 多继承
        pass
    sxz = SunWukong() # 孙悟空
    sxz.chitao() # 会吃桃⼦
    sxz.fei() # 会⻜
    

    多继承中, 存在着这样⼀个问题. 当两个⽗类中出现了重名⽅法的时候 , 查找⽗类⽅法 , 即MRO(method resolution order) 问题. 在python中这是⼀个很复杂的问题. 因为在不同的python版本中使⽤的是不同的算法来完成MRO的.

    python中类的种类(继承需要):

    python2x版本中存在两种类

    • ⼀个叫经典类. 在python2.2之前. ⼀直使⽤的是经典类. 经典类在基类的根如果什么都不写会报错
    • 经典类: 基类不继承object,查询规则 依靠:深度优先的原则.
    • 记住⼀个原则. 在经典类中采⽤的是 深度优先遍历⽅案 / 即: ⼀条路走到头. 然后再回来. 继续找下⼀个
    • ⼀个叫新式类. 在python2.2之后出现了新式类. 新式类的特点是基类继承object类 , 新式类比经典类执行效率高
    # python2x
    class A:  # 经典类
        pass
    
    class B(object):  # 新式类
        pass
    

    python3x版本中只有一种类 / 新式类

    • python3中使⽤的都是 新式类. 如果基类谁都不继承. 那这个类会默认继承 object
    • object是最上面的类, python3以后默认了object,不用写了
    # python3x:(默认继承object)
    class C: # 新式类
         pass
    

    经典类的多继承

    • python3中不存在经典类 , 经典类的MRO , 是一种树形结构遍历,默认 从左向右
    • 记住⼀个原则. 在经典类中采⽤的是 深度优先遍历⽅案 / 即: ⼀条路走到头. 然后再回来. 继续找下⼀个
    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())
    #  类的MRO: Foo-> H -> G -> F -> E -> D -> B -> A -> C.  深度优先遍历 (经典类中采用的遍历方法)
    

    mro序列

    • 工作中用mro()方法研究新式类的继承顺序
    • print(A.mro())

    新式类的多继承 mro序列

    • 新式类: 基类继承object,查询规则: mro算法.

    mro序列

    表头和表尾 (表尾可为None)

    • 表头 列表的第一个元素
    • 表尾 列表中表头以外的元素集合(可以为空)

    列表之间的+操作

    • [A,B,C] : 表头: A 表尾: [B,C]
    • [A] : 表头: A 表尾: []

    计算mro(A)方式

    class O:
        pass
    
    class D(O):
        pass
    
    class E(O):
        pass
    
    class F(O):
        pass
    
    class B(D,E):
        pass
    
    class C(E,F):
        pass
    
    class A(B,C):
        pass
    
    # a = A()
    # a.func()
    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])
           = [B,D] + merge([O], [E,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,O]
    
    mro(A) = mro(A(B,C))
           = [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,O]
            
    # 解题过程:
    1.先从上到下,列出每个类的线性表达式.
    2.列出的线性表达式中如果有多个表达式的话,需要进行化简.
    3.最终的子类也使用线性表达式表示,由于有多个父类,也需要进行化简.
    
    线性表达式有两个部分组成:第一个类名称为头部,剩余的部分称为尾部.
    化简:从多个线性表达式中第一个表达式的头部开始抽取,如果这个类名不在其他的线性表达式中的尾部出现的话,则可以抽取;若第一个表达式的头部的类名在其他的表达式中的尾部出现的话,则不能抽取;此时,从下一个表达式的头部开始抽取,前面的表达式保持原样.以备下一次抽取,下一次抽取的过程依然从第一个表达式的头部开始,重复上面的过程.
    
    

    可以用拓扑排序开直接分析mro排序,最下面的子类入度为0 ,从左向右执行,一层一层由左向右执行,一直找入度为0的父类

  • 相关阅读:
    c++求最大公约数、最小公倍数
    五个简单的shell脚本
    微信小程序slot(一)
    小程序详解子传父
    小程序封装组件详解父传子
    小程序生命周期详解
    小程序之confirm-type改变键盘右下角的内容和input按钮详解
    小程序之按钮你不知道的v2
    小程序image图片缩小不变形
    小程序之navigator跳转方式
  • 原文地址:https://www.cnblogs.com/fanxss/p/11147217.html
Copyright © 2011-2022 走看看