zoukankan      html  css  js  c++  java
  • 继承与派生

    1 什么是继承

    2 经典类与新式类

    3 属性查找

    4 子类重用父类的方法

    5 继承的实现原理

    6 子类中调用父类的方法


    1 什么是继承

    是一种新建类的方式,新建的类称为子类,子类会遗传父类的属性,可以减少代码冗余在python中,子类(派生类)可以继承一个或者多个父类(基类,超类)

    class Parent1: #定义父类
        pass
    class Parent2(object): #定义父类
        pass
    class Sub1(Parent1): #单继承,基类是ParentClass1,派生类是SubClass
        pass
    class Sub2(Parent1,Parent2): #python支持多继承,用逗号分隔开多个继承的类
        pass
    
    
    print(Sub1.__bases__)#__base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类
    print(Sub2.__bases__)
    print(Parent1.__bases__)
    print(Parent2.__bases__)

    2 经典类与新式类

    1.只有在python2中才分新式类和经典类,python3中统一都是新式类

    2.在python2中,没有显式的继承object类的类,以及该类的子类,都是经典类

    3.在python2中,显式地声明继承object的类,以及该类的子类,都是新式类

    4.在python3中,无论是否继承object,都默认继承object,即python3中所有类均为新式类

    3 属性查找

    先从自己类中查找,再然后再去父类中找...直到最顶级的父类。

    #属性查找
    class Foo:
        def f1(self):
            print('Foo.f1')
    
        def f2(self): #self=obj
            print('Foo.f2')
            self.f1() #obj.f1()
    
    class Bar(Foo):
        def f1(self):
            print('Bar.f1')
    
    obj=Bar()
    print(obj.__dict__)
    obj.f2()
    '''{}
    Foo.f2
    Bar.f1
    '''

    4 子类重用父类的方法

    #方法一(不建议用)
    class OldboyPeople:
        school = 'Oldboy'
    
        def __init__(self, name, age, sex):
            self.name = name
            self.age = age
            self.sex = sex
    
        def tell_info(self):
            print('<名字:%s 年龄:%s 性别:%s>' %(self.name,self.age,self.sex))
    
    class OldboyStudent(OldboyPeople):
        def __init__(self,name,age,sex,course,stu_id):
            OldboyPeople.__init__(self,name,age,sex)#调用父类的方法
            self.course=course
            self.stu_id=stu_id
    
        def learn(self):
            print('%s is learning' %self.name)
    
        def tell_info(self):
            print('我是学生:',end='')
            # self.tell_info() #stu1.tell_info()
            OldboyPeople.tell_info(self) #调用父类的方法
    
    stu1=OldboyStudent('牛榴弹',18,'male','Python',1)
    stu1.tell_info()
    #方法二:使用super关键字
    class OldboyPeople:
        school = 'Oldboy'
    
        def __init__(self, name, age, sex):
            self.name = name
            self.age = age
            self.sex = sex
    
        def tell_info(self):
            print('<名字:%s 年龄:%s 性别:%s>' %(self.name,self.age,self.sex))
    
    class OldboyStudent(OldboyPeople):
        def __init__(self,name,age,sex,course):
            # OldboyPeople.__init__(self,name,age,sex)
            super(OldboyStudent,self).__init__(name,age,sex)#使用super关键字
            self.course=course
    
        def tell_info(self):
            print('我是学生: ',end='')
            # OldboyPeople.tell_info(self)
            super(OldboyStudent,self).tell_info() #使用super关键字
    
    stu1=OldboyStudent('egon',18,'male','python')
    # print(stu1.name,stu1.age,stu1.sex,stu1.course)
    stu1.tell_info()

    5 继承的实现原理

          1、继承顺序

        

    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中才分新式类与经典类

    2、继承原理

    为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。
    而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:
    1.子类会先于父类被检查
    2.多个父类会根据它们在列表中的顺序被检查
    3.如果对下一个类存在两个合法的选择,选择第一个父类

    >>> F.mro() #等同于F.__mro__
    [<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>
    ]

    6 子类中调用父类的方法

    #方法一:指名道姓,即父类名.父类方法()
    
    #_*_coding:utf-8_*_
    
    class Vehicle: #定义交通工具类
         Country='China'
         def __init__(self,name,speed,load,power):
             self.name=name
             self.speed=speed
             self.load=load
             self.power=power
    
         def run(self):
             print('开动啦...')
    
    class Subway(Vehicle): #地铁
        def __init__(self,name,speed,load,power,line):
            Vehicle.__init__(self,name,speed,load,power)
            self.line=line
    
        def run(self):
            print('地铁%s号线欢迎您' %self.line)
            Vehicle.run(self)
    
    line13=Subway('中国地铁','180m/s','1000人/箱','',13)
    line13.run()
    #方法二:super()
    
    class Vehicle: #定义交通工具类
         Country='China'
         def __init__(self,name,speed,load,power):
             self.name=name
             self.speed=speed
             self.load=load
             self.power=power
    
         def run(self):
             print('开动啦...')
    
    class Subway(Vehicle): #地铁
        def __init__(self,name,speed,load,power,line):
            #super(Subway,self) 就相当于实例本身 在python3中super()等同于super(Subway,self)
            super().__init__(name,speed,load,power)
            self.line=line
    
        def run(self):
            print('地铁%s号线欢迎您' %self.line)
            super(Subway,self).run()
    
    class Mobike(Vehicle):#摩拜单车
        pass
    
    line13=Subway('中国地铁','180m/s','1000人/箱','',13)
    line13.run()

    即使没有直接继承关系,super仍然会按照mro继续往后查找

    #A没有继承B,但是A内super会基于C.mro()继续往后找
    class A:
        def test(self):
            super().test()
    class B:
        def test(self):
            print('from B')
    class C(A,B):
        pass
    
    c=C()
    c.test() #打印结果:from B
    
    
    print(C.mro())
    #[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
    #指名道姓
    class A:
        def __init__(self):
            print('A的构造方法')
    class B(A):
        def __init__(self):
            print('B的构造方法')
            A.__init__(self)
    
    class C(A):
        def __init__(self):
            print('C的构造方法')
            A.__init__(self)
    
    class D(B,C):
        def __init__(self):
            print('D的构造方法')
            B.__init__(self)
            C.__init__(self)
    
    f1=D() #A.__init__被重复调用
    '''
    D的构造方法
    B的构造方法
    A的构造方法
    C的构造方法
    A的构造方法
    '''
    
    #使用super()
    class A:
        def __init__(self):
            print('A的构造方法')
    class B(A):
        def __init__(self):
            print('B的构造方法')
            super(B,self).__init__()
    
    class C(A):
        def __init__(self):
            print('C的构造方法')
            super(C,self).__init__()
    
    class D(B,C):
        def __init__(self):
            print('D的构造方法')
            super(D,self).__init__()
    
    f1=D() #super()会基于mro列表,往后找
    '''
    D的构造方法
    B的构造方法
    C的构造方法
    A的构造方法
    '''
    指名道姓与super()的区别

    当你使用super()函数时,Python会在MRO列表上继续搜索下一个类。只要每个重定义的方法统一使用super()并只调用它一次,那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次(注意注意注意:使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表)

  • 相关阅读:
    软件工程14—第09组 Beta冲刺(2/4)
    软件工程13—第09组 Beta冲刺(1/4)
    软件工程12—第09组 Alpha事后诸葛
    软件工程11—第09组 Alpha冲刺(4/4)
    软件工程10—第09组 Alpha冲刺(3/4)
    软件工程09—第09组 Alpha冲刺(2/4)
    软件工程08—第09组 Alpha冲刺(1/4)
    软件工程07—第09组 团队Git现场编程实战
    软件工程06—亚瑟王の十三水2.0
    第06组 Alpha冲刺(4/6)
  • 原文地址:https://www.cnblogs.com/snailgirl/p/8513785.html
Copyright © 2011-2022 走看看