面向对象 继承 (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的父类

posted @ 2019-07-05 21:57  樊xs  阅读(519)  评论(0编辑  收藏  举报