zoukankan      html  css  js  c++  java
  • 面向对象之继承与派生

    一、继承

      1、含义:继承指的是类与类之间的关系,是一种什么“是”什么的关系,继承的功能之一就是用来解决代码重用问题。

      2、特点:继承是一种创建新类的方式,在Python中,新建的类可以继承一个或多个父类,而父类又可以称为基类或超类,新建的类称为派生类或子类。

      3、继承的分类

        Python中类的继承可分为单继承和多继承。

    # 单继承
    class Hero:
        '''
        父类
        '''
        def __init__(self,nickname,aggressivity,life_valid):
            self.nickname = nickname
            self.aggressivity = aggressivity
            self.life_valid = life_valid
        def attack(self,target):
            target.life_valid -= self.aggressivity
            if target.life_valid <= 0:
                print('%s is died'%target.nickname)
    
    class Gaylen(Hero): #单继承,基类是Hero,派生类是Gaylen
        '''
        继承父类
        '''
        pass
    class Hand_of_Knoxus(Hero):#单继承,基类是Hero,派生类是Hand_of_Knoxus
    ''' 继承父类 ''' 
      pass
    herol = Gaylen('大盖伦',60,300)
    hero2
    = Hand_of_Knoxus('诺手',70,280)
    print(herol.__dict__) # {'nickname': '大盖伦', 'aggressivity': 60, 'life_valid': 300}
    herol.attack(hero2)
    print(hero2.life_valid) # 220

    #多继承
    class Parent1: #定义父类一
      pass
    class Parent2: #定义父类二
      pass
    class son1(Parent1,Parent2): #Python支持多继承,用逗号分隔多个继承的类
      pass

    #查看继承
    print(
    son1.__base__)# __base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类
    #(<class '__main__.Parent1'>)

    print(son1.__bases__) #(<class '__main__.Parent1'>,<class '__main__.Parent2'>)
    
    

      4、单继承中对象属性的查找顺序

        <1>对象自身属性(__init__方法)里查找

        <2>对象自身里没有,在自己的类里找

        <3>自己的类里没有,在父类里查找 

    # 属性查找
    class Father:
        def f1(self):
            print('from Father.f1')
        def f2(self):
            print('from Father.f2')
            self.f1() # 等价于person.f1(),查找:person自身->自身的类(Son)
    class Son(Father):
        def f1(self):
            print('from Son.f1')
    
    person = Son()
    print(person.__dict__) # {} 自身没有定义属性
    person.f2() # 单继承查找顺序:person自身—>自身的类(Son)->父类(Father)

     二、派生

      1、含义:

         派生:子类也可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类),对象属性查找中按照自身,后类,再父类的顺序,当某些属性自身类中有而父类无或者两者都有时,优先选择自身类中的属性。

      2、实例:

    class Hero:
        '''
        父类
        '''
        def __init__(self,nickname,aggressivity,life_valid):
            self.nickname = nickname
            self.aggressivity = aggressivity
            self.life_valid = life_valid
        def attack(self,target):
            target.life_valid -= self.aggressivity
            if target.life_valid <= 0:
                print('%s is died'%target.nickname,'
    from Hero.attack')
    
    class Gaylen(Hero):
        '''
        继承父类
        '''
        camp = 'Desmarcia'
        def attack(self,target):
            target.life_valid -= self.aggressivity
            if target.life_valid <= 0:
                print('%s is died'%target.nickname,'
    from Gaylen.attack')
    class Hand_of_Knoxus(Hero):
        '''
        继承父类
        '''
        camp = 'Desmarcia'

    herol = Gaylen('大盖伦',80,190) hero2 = Hand_of_Knoxus('诺手',100,150) herol.attack(hero2) herol.attack(hero2) ''' 输出: 诺手 is died from Gaylen.attack '''

     

    三、继承的实现原理

      1、Python对于你定义的每一个类,会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表。

      2、为了实现继承,Python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。而这个MRO列表的构造是通过一个C3线性化算法来实现的。简单来说就是合并所有父类的MRO列表并遵循下述原则:

      <1>子类会优先于父类被检查

      <2>多个子类会根据它们在列表中的顺序被检查。

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

      注意:

        在Java和C#只能继承一个父类,而Python中子类可以继承多个父类,如果继承了多个父类,那么属性的查找方式有两种,分别是:深度优先和广度优先。

        通过继承机制,可以利用已有的数据类型来定义新的数据类型。所定义的新的数据类型不仅拥有新定义的

    成员,而且还同时拥有旧的成员。我们称已存在的用来派生新类的类为父类,也就是基类。

    四、多继承下的属性查找(广度优先)

    class A(object):
        def test(self):
            print('from A')
    class B(A):
        # def test(self):
        #     print('from B')
        pass
    class C(A):
        # def test(self):
        #     print('from C')
        pass
    class D(B):
        # def test(self):
        #     print('from D')
        pass
    class E(C):
        # def test(self):
        #     print('from E')
        pass
    class F(D,E):
        # def test(self):
        #     print('from F')
        pass
    
    f = F()
    f.test() # 查找顺序:f->F类->D类->B类->E类->C类->A类
    print(F.mro()) # 新式类中才有这个属性可以查看线性列表,经典类没有
    # [<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>,
    # <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
    View Code

     

    五、经典类和新式类

      1、在Python2中-》经典类:没有继承object的类,以及他的子类都称之为经典类。 深度优先查找

        如下:

    class Father:
        pass
    class Son(Father):
        pass

      2、在Python2中-》新式类:有继承object的类,以及他的子类都称之为新式类。 广度优先查找

        如下:

    class Father(object):
        pass
    class Son(Father):
        pass

      3、在Python3中-》新式类(无经典类之分):一个类没有继承object类,就默认继承object。 广度优先查找

    class Father:
         pass
     print(Father.__bases__) # (<class 'object'>,) 在Python中,每个类有一个__bases__属性,列出其基类

      补充:

     六、在子类中重用父类的属性

      1、在子类派生的新的方法中重用父类的方法,有两种实现方式:

        方式一:指明道姓(不依赖继承)

        方式二:super() (依赖继承)-->遵照MRO列表顺序

      2、方式一:   

    class Hero:
        
        # 父类
        
        def __init__(self,nickname,aggressivity,life_valid):
            self.nickname = nickname
            self.aggressivity = aggressivity
            self.life_valid = life_valid
        def attack(self,target):
            target.life_valid -= self.aggressivity
            if target.life_valid <= 0:
                print('%s is died'%target.nickname,'
    from Hero.attack')
    
    class Gaylen(Hero):
        
        #继承父类
        
        camp = 'Desmarcia'
        def __init__(self,nickname,aggressivity,life_valid,arms):
            Hero.__init__(self,nickname,aggressivity,life_valid) # 指名道姓地重用方式
            self.arms = arms
        def attack(self,target):
            Hero.attack(self,target) # 指名道姓地重用方式,不依赖继承
            print('from Gaylenlen ...')
    
    class Hand_of_Knoxus(Hero):
    
        #继承父类
    
        camp = 'Desmarcia'
    herol = Gaylen('大盖伦',80,190,'大刀')
    hero2 = Hand_of_Knoxus('诺手',100,150)
    herol.attack(hero2)
    print(hero2.life_valid) # 70
    print(herol.arms) # 大刀
    View Code

      3、方式二: 

    class Hero:
        
        # 父类
        
        def __init__(self,nickname,aggressivity,life_valid):
            self.nickname = nickname
            self.aggressivity = aggressivity
            self.life_valid = life_valid
        def attack(self,target):
            target.life_valid -= self.aggressivity
            if target.life_valid <= 0:
                print('%s is died'%target.nickname,'
    from Hero.attack')
    
    class Gaylen(Hero):
        
        #继承父类
        
        camp = 'Desmarcia'
        def __init__(self,nickname,aggressivity,life_valid,arms):
            Hero.__init__(self,nickname,aggressivity,life_valid) # 指名道姓地重用方式
            self.arms = arms
        def attack(self,target):
            Hero.attack(self,target) # 指名道姓地重用方式,不依赖继承
            print('from Gaylenlen ...')
    
    class Hand_of_Knoxus(Hero):
    
        #继承父类
    
        camp = 'Desmarcia'
    herol = Gaylen('大盖伦',80,190,'大刀')
    hero2 = Hand_of_Knoxus('诺手',100,150)
    herol.attack(hero2)
    print(hero2.life_valid) # 70
    print(herol.arms) # 大刀
    View Code

      4、super()继承查找顺序  

    class A:
        def f1(self):
            print('from A')
            super().f1() # 从最近查找的MRO节点继续往后找(此时按照的是C的MRO列表),故B虽不是A的父类,但仍会继承B
    class B:
        def f1(self):
            print('from B')
    class C(A,B):
        pass
    c = C()
    c.f1() # from A -->from B
    print(C.mro())
    # 查找顺序
    # [<class '__main__.C'>,
    # <class '__main__.A'>,
    # <class '__main__.B'>,
    # <class 'object'>]
  • 相关阅读:
    EntityFramework优缺点
    领导者与管理者的区别
    七个对我最好的职业建议(精简版)
    The best career advice I’ve received
    Difference between Stored Procedure and Function in SQL Server
    2015年上半年一次通过 信息系统项目管理师
    Difference between WCF and Web API and WCF REST and Web Service
    What’s the difference between data mining and data warehousing?
    What is the difference between a Clustered and Non Clustered Index?
    用new创建函数的过程发生了什么
  • 原文地址:https://www.cnblogs.com/schut/p/8612572.html
Copyright © 2011-2022 走看看