zoukankan      html  css  js  c++  java
  • 面向对象编程之——继承(介绍,子类派生的新方法中重用父类功能,属性查找,继承实现原理,Mixins机制)

    一、继承介绍

    1、什么是继承
    继承是一种新建类的方式,新建的类称之为子类,
    被继承的类称之为父类、基类、超类
        python支持多继承,用逗号分隔开多个继承的类
     查看继承:派生类名.__bases__ #__base__只查看从左到右继承的第一个父类,__bases__则是查看所有继承的父类
    2、为何要继承
    子类会遗传父类的属性,所以继承是用来解决类与类之间代码冗余问题
      PS:类是为了解决对象与对象之间代码冗余问题

    3、如何实现继承
    ps:单继承能更好的反应什么是什么的关系
    # 继承案列:
    class OldboyPeople:
        school = "oldboy"
    
    class Student(OldboyPeople):
        def __init__(self,name,age,gender,stud_id,course):
            self.name = name
            self.age = age
            self.gender = gender
            self.stu_id = stud_id
            self.course = course
    
        def choose(self):
            print('%s 正在选课' %self.name)
    
    class Teacher(OldboyPeople):
        def __init__(self,name,age,gender,salary,level):
            self.name = name
            self.age = age
            self.gender = gender
            self.salary = salary
            self.level = level
    
        def score(self,stu,num):
            stu.num = num
    
    stu1=Student("艾利克斯",73,'male',1001,"python全栈开放")
    tea1=Teacher("egon",18,'male',2000,10)
    
    print(stu1.school)

    二、在子类派生的新方法中重用父类的功能

    方式一:指名道姓地调用某一个类的函数
    特点:不依赖于继承关系
    class OldboyPeople:
        school = "oldboy"
        #             空对象,"艾利克斯",73,'male'
        def __init__(self,name,age,gender):
            self.name = name
            self.age = age
            self.gender = gender
    
        def f1(self):
            print('1111111')
    
    class Student(OldboyPeople):
        #            空对象,"艾利克斯",73,'male',1001,"python全栈开放"
        def __init__(self,name,age,gender,stu_id,course):
            OldboyPeople.__init__(self,name,age,gender)  # OldboyPeople.__init__(空对象,"艾利克斯",73,'male')
            self.stu_id = stu_id
            self.course = course
    
        def choose(self):
            print('%s 正在选课' %self.name)
    
        def f1(self):
            OldboyPeople.f1(self)
            print("22222")
    
    class Teacher(OldboyPeople):
        def score(self,stu,num):
            stu.num = num
    
    stu1=Student("艾利克斯",73,'male',1001,"python全栈开放")
    # tea1=Teacher("egon",18,'male',2000,10)
    
    stu1.f1()

    方式二:调用super(自己的类名,self)会返回一个特殊的对象,super(自己的类名,self).属性,会参照属性查找发起的那个类的mro列表去它父类中查找属性

     特点:严格依赖于继承关系

    #1
    class OldboyPeople:
        school = "oldboy"
        #             空对象,"艾利克斯",73,'male'
        def __init__(self,name,age,gender):
            self.name = name
            self.age = age
            self.gender = gender
    
        def f1(self):
            print('1111111')
    
    class Student(OldboyPeople):
        def __init__(self,name,age,gender,stu_id,course):
            # OldboyPeople.__init__(self,name,age,gender)  # OldboyPeople.__init__(空对象,"艾利克斯",73,'male')
            super(Student,self).__init__(name,age,gender)
            self.stu_id = stu_id
            self.course = course
    
    
        def choose(self):
            print('%s 正在选课' %self.name)
    
        def f1(self):
            # OldboyPeople.f1(self)
            # super().f1()
            print("22222")
    
    # print(Student.mro())
    stu1=Student("艾利克斯",73,'male',1001,"python全栈开放")
    # print(stu1.__dict__)
    stu1.f1()
    
    
    #2: class A:     def test(self):         super().test() class B:     def test(self):         print('from B') class C(A,B):     pass
    
     c=C() print(C.mro()) c.test()
    
     obj=A() obj.test()
    
    #3:
    class A:
        def test(self):
            print('A---->test')
            super().aaa()
    class B:
        def test(self):
            print('B---->test')
    
        def aaa(self):
            print('B---->aaa')
    
    class C(A,B):
        def aaa(self):
            print('C----->aaa')
    
    c=C()
    print(C.mro())
    c.test()

    三、属性查找

    # 例1:有了继承关系,对象在查找属性时,先从对象自己的__dict__中找,如果没有则去子类中找,然后再去父类中找
    class Foo:
        def f2(self):
            print("Foo.f2")
    
        def f1(self):
            print('Foo.f1')
            self.f2()  # obj.f2()
    
    class Bar(Foo):
        def f2(self):
            print("Bar.f2")
    
    obj = Bar()
    obj.f1()
    
    
    # 例2:父类如果不想让子类覆盖自己的方法,可以在方法名前加前缀__
    class Foo:
        def __f2(self):  # _Foo__f2
            print("Foo.f2")
    
        def f1(self):
            print('Foo.f1')
            self.__f2()  # obj._Foo__f2()
    
    class Bar(Foo):#父类为Foo
        def __f2(self):  # _Bar__f2
            print("Bar.f2")
    
    obj = Bar()
    obj.f1()

    四、继承的实现原理

    # coding:utf-8 (在python2中要写文件头才能保证不乱码,python3底层会有优化机制不用写)
    1、 补充知识:
    新式类:但凡是继承了object类的子类,以该子类子子孙孙类都称之为新式类
    经典类:没有继承了object类的子类,以该子类子子孙孙类都称之为经典类

    python3中无论是否继承object,都默认继承object,即python3中全都是新式类。
    python2中才有经典类
    python2中没有显式的继承object的类,以及该类的子类,都是经典类;
    python2中显式地声明继承object的类,以及该类的子类,都是新式类。
    pyhon2中新式类要主动继承,手动加上object,加上文件头

    class Foo(object):
    pass
    print(Foo.__bases__) #通过类的内置属性__bases__可以查看类继承的所有父类

    2、 继承的实现原理
    继承(先抽象再继承):是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构。
    对于你定义的每一个类,Python都会计算出一个方法解析顺序(MRO)列表,该MRO列表就是一个简单的所有基类的线性顺序列表
    python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止
    查找顺序:(1)子类会先于父类被检查
         (2)
    多个父类会根据它们在列表中的顺序被检查
         (3)
    如果对下一个类存在两个合法的选择,选择第一个父类
    ps:
    1.由对象发起的属性查找,会从对象自身的属性里检索,没有则会按照对象的类.mro()规定的顺序依次找下去,
    2.由类发起的属性查找,会按照当前类.mro()规定的顺序依次找下去

    2.1 菱形问题(有时也称死亡钻石):一个子类继承的多条件分支最终汇聚到一个非object类,在菱形继承下
    新式类与经典类关于属性查找的方式不同

    新式类:广度优先
    经典类:深度优先
    # 例1:非菱形继承,经典类与新式类的属性查找顺序都一样
    class E:
         def test(self):
             print('from E')
        pass
    
    class F:
        def test(self):
            print('from F')
    
    class B(E):
         def test(self):
             print('from B')
        pass
    
    class C(F):
        def test(self):
            print('from C')
    
    class D:
        def test(self):
            print('from D')
    
    class A(B, C, D):
         def test(self):
             print('from A')
        pass
    
    obj=A()
    obj.test()
    # 例2:菱形继承
    class G(object): # 在python2中,未继承object的类及其子类,都是经典类
        def test(self):
            print('from G')
        pass
    
    class E(G):
        def test(self):
            print('from E')
        pass
    
    class F(G):
        def test(self):
            print('from F')
        pass
    
    class B(E):
        def test(self):
            print('from B')
        pass
    
    class C(F):
        def test(self):
            print('from C')
        pass
    
    class D(G):
        def test(self):
            print('from D')
        pass
    
    class A(B,C,D):
        def test(self):
            print('from A')
        pass
    
    obj=A()
    obj.test()
    
    print(A.mro())

    五、mixins机制

    mixins机制 遵循'is-a'关系
    #不合理
    class Vehicle:  # 交通工具
        def fly(self):
            '''
            飞行功能相应的代码        
            '''
            print("I am flying")
    
    class CivilAircraft(Vehicle):  # 民航飞机
        pass
    
    class Helicopter(Vehicle):  # 直升飞机
        pass
    
    class Car(Vehicle):  # 汽车并不会飞,但按照上述继承关系,汽车也能飞了
        pass
    #Mixins机制
    class Vehicle:  # 交通工具
        pass
    
    
    class FlyableMixin:
        def fly(self):
            '''
            飞行功能相应的代码        
            '''
            print("I am flying")
    
    
    class CivilAircraft(FlyableMixin, Vehicle):  # 民航飞机
        pass
    
    
    class Helicopter(FlyableMixin, Vehicle):  # 直升飞机
        pass
    
    
    class Car(Vehicle):  # 汽车
        pass
    
    # ps: 采用某种规范(如命名规范)来解决具体的问题是python惯用的套路

    使用Mixin类实现多重继承要非常小心

    • 首先它必须表示某一种功能,而不是某个物品,python 对于mixin类的命名方式一般以 Mixin, able, ible 为后缀
    • 其次它必须责任单一,如果有多个功能,那就写多个Mixin类,一个类可以继承多个Mixin,为了保证遵循继承的“is-a”原则,只能继承一个标识其归属含义的父类
    • 然后,它不依赖于子类的实现
    • 最后,子类即便没有继承这个Mixin类,也照样可以工作,就是缺少了某个功能。(比如飞机照样可以载客,就是不能飞了)

    ​ Mixins是从多个类中重用代码的好方法,但是需要付出相应的代价,我们定义的Minx类越多,子类的代码可读性就会越差,并且更恶心的是,在继承的层级变多时,代码阅读者在定位某一个方法到底在何处调用时会晕头转向

    
    
  • 相关阅读:
    yuv文件并行解析播放
    视频解析
    有意思的并查集讲解 收藏
    C++输入输出重载
    python 同步IO
    多线程与多进程的理解
    centos7 配置redis
    linux中的raid
    form表单系列中文件上传及预览
    centos7 安装swftools Apache_OpenOffice
  • 原文地址:https://www.cnblogs.com/guojieying/p/13446814.html
Copyright © 2011-2022 走看看