OOP三大特征之继承

  • 继承

  • 什么是继承:两个对象之间的关系,一个称为子类,一个称为父类,其中子类继承着父类的属性以及方法技能,可以直接使用。(值得注意的是:在python3中所有创建的类都直接或间接,隐性或显性的继承object类,如果没有显示继承某个类,则默认继承的是object类,又称为新式类)

  • 为什么要使用继承:减少代码的复用

  • 用代码如何表示

  • class Base:
        character  = '我是父类'
        def want_basketball(self):\
            print('教练我想打篮球')
    
    class SubClass(Base):               # 通过在子类的括号之中加父类的名称
        pass
    
    obj = SubClass()
    obj.want_basketball()               # 直接调用父类的方法 如果属性和方法完全一样的话
    print(obj.character)

    比如好人,坏人,黄种人,白种人,黑人都是人这个大类的继承,而他们都是抽象而生成人这个类的。

  • 那么当子类和父类有属性和方法有冲突时,是不是就不可以用继承方法呢?显然不是,一般来说我们可以将子类和父类的共同特征都提取出来,专业名词可以称之为抽象,将抽象完的一个新的类作为共同大类,供上述子类和父类使用。

  • 就以足球和篮球运动员为例,对于他们来说都是人类,都有名字性别和身高等特征,但是他们会的技能不一样
  • class Person:
        def __init__(self,name,height,gender):          # 定义抽象得来的公共类
            self.name = name
            self.height = height
            self.gender = gender
    
    class FootBallPlayer(Person):                       # 通过子类名括号里面加抽象父类名起到继承的作用
        def Skill(self):
            print('%s会踢足球'%(self.name))
    
    class BasketBallPlayer(Person):
        def Skill1(self):
            print('%s会打篮球'%(self.name))
    
    
    
    Kobe = BasketBallPlayer('kobe Bryant','189','male')     # 名字身高等信息就不需要通过父类调用,直接子类调用
    Kobe.Skill1()
    Messi = FootBallPlayer('Lion Messi','176','male')
    Messi.Skill()
  • 存在继承关系后的属性查找

  • 一个类必然继承另一个类,被继承的类也有可能继承了其他类,相当于C继承B,B又继承A

  • 此时查找属性的顺序是:

    对象本身的名称空间 - > 类的名称空间 -> 父类的名称空间 -> 父类的父类名称空间 ->...object类

    会沿着继承关系一直往后查找,直到找到为止,由于object是所有类的根类,所以如果找不着最后都会查找object类!

  • class Foo:
        def f1(self):
            print('Foo.f1')
    
        def f2(self):
            print('Foo.f2')
            self.f1()
    
    class Bar(Foo):
        def f1(self):
            print('Bar.f1')
    
    
    b=Bar()
    b.f1()
    #输出 Bar.f1
    b.f2()
    #输出 Foo.f2
  • 派生和覆盖

  • 派生的定义:当父类提供的属性无法完全满足子类的需求时,子类可以增加自己的属性或方法,或者覆盖父类已经存在的属性,此时子类称之为父类的派生类;

  • 覆盖的定义:如果子类中出现于与父类相同的属性以及方法时,程序要调用,会优先使用子类中的属性。
  • 很多情况下 子类中的代码与父类中仅有小部分不同,却不得不在子类定义新的方法,这时候可以在子类中调用父类已有的方法,来完成大部分工作,子类仅需编写一小部分与父类不同的代码即可

  • 有两种方式可以重用父类的属性和方法

  • 使用类名直接调用 ,该方式与继承没有关系,即时没有继承关系,也可以调用
  • 使用super()
  • class Person:
        def __init__(self,name,height,gender):          # 定义抽象得来的公共类
            self.name = name
            self.height = height
            self.gender = gender
    
    class FootBallPlayer(Person):                       # 通过子类名括号里面加抽象父类名起到继承的作用
        def __init__(self,name,height,gender,field):    # 如果不写这两行 将不能调用name height gender属性
            super().__init__(name,height,gender)        # 重用父类中的代码,防止覆盖了父类中的init方法
            self.field = field
        def Skill(self):
            print('%s会踢足球'%(self.name))
            print(self.height,self.gender,self.field)
    Messi = FootBallPlayer('Lion Messi','176','male','grass')
    Messi.Skill()
  • 组合

  • 当两个类之间没有太大的联系的时候,或者说它们不属于同类时,当一个对象要使用另一个对象的属性,这就叫做组合的概念。

  • class Equip:  # 武器装备类
        def fire(self):
            print('release Fire skill')
    
    
    class Riven:  # 英雄Riven的类,一个英雄需要有装备,因而需要组合Equip类
        camp = 'Noxus'
    
        def __init__(self, nickname):
            self.nickname = nickname
            self.equip = Equip()  # 用Equip类产生一个装备,赋值给实例的equip属性
    
    
    r1 = Riven('锐雯雯')
    r1.equip.fire()  # 可以使用组合的类产生的对象所持有的方法
  • 继承实现的原理

  • 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'>
  • 所有父类的MRO列表并遵循如下三条准则:

    1.子类会先于父类被检查

    2.多个父类会根据它们在列表中的顺序被检查

    3.如果对下一个类存在两个合法的选择,选择第一个父类

猜你喜欢

转载自www.cnblogs.com/ITchemist/p/11247632.html