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的父类

  • 相关阅读:
    Windows 8实例教程系列 开篇
    qt 开发发布于 windeploy.exe
    qt qoci 测试验证
    vmware vmx 版本不兼容
    qt oracle
    vc qt dll
    QOCIDriver unable to create environment
    qoci 编译完 放置位置 具体根据情况
    calling 'lastError' with incomplete return type 'QSqlError' qsqlquer
    Hbase 操作工具类
  • 原文地址:https://www.cnblogs.com/fanxss/p/11147217.html
Copyright © 2011-2022 走看看