• 继承的应用,继承实现原理,super(),多继承的代码规范,组合


    一、继承的应用

    继承的应用:
    对于你定义的每一个类,Python都会计算出一个方法解析顺序(MRO)列表,该MRO列表就是一个简单的所有基类的线性顺序列表,
    MRO列表的构造是通过一个C3线性化算法来实现的,我们无需深究该算法的数学原理,它实际上就是合并所有父类的MRO列表,且在查找属性时,
    Python会基于MRO列表按照从左到右的顺序依次查找基类,直到找到第一个匹配这个属性的类为止。

    在Python中子类可以同时继承多个父类,在子类继承了多个父类时,经典类与新式类会有不同MRO,分别对应属性的两种查找方式:深度优先和广度优先

    class Student:
        school = "虹桥校区"
    
        def __init__(self,name,age,gender):
            self.name = name
            self.age = age
            self.gender = gender
    
        def choose(self):
            print("%s 选课成功" %self.name)
    
    stu1 = Student("jack",18,"male")
    stu2 = Student("tom",19,"male")
    stu3 = Student('lili',29,"female")
    
    class Teacher:
        school = "虹桥校区"
    
        def __init__(self,name,age,gender,level):
            self.name = name
            self.age = age
            self.gender = gender
            self.level = level
    
        def score(self):
            print("%s 正在为学生打分" %self.name)
    
    tea1 = Teacher('egon',18,"male",10)
    tea2 = Teacher('lxx',38,"male",3)
    

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

    方式一: 指名道姓地引用某一个类的函数,与继承无关

    子类可以派生出自己新的属性,在进行属性查找时,子类中的属性名会优先于父类被查找,例如每个老师还有职称这一属性,我们就需要在Teacher类中定义该类自己的--init--覆盖父类的

    class People:
        school = "虹桥校区"
    
        def __init__(self,name,age,gender):
            self.name = name
            self.age = age
            self.gender = gender
    
    class Student(People):
        def choose(self):
            print("%s 选课成功" %self.name)
    
    class Teacher(People):
        #            空对象,'egon',18,"male",10
        def __init__(self,name,age,gender,level):
            People.__init__(self,name,age,gender)
    
            self.level = level
    
        def score(self):
            print("%s 正在为学生打分" %self.name)
    
    stu1 = Student("jack",18,"male")
    stu2 = Student("tom",19,"male")
    stu3 = Student('lili',29,"female")
    
    
    tea1 = Teacher('egon',18,"male",10)  # 空对象,'egon',18,"male",10
    tea2 = Teacher('lxx',38,"male",3)
    
    # print(stu1.school)
    # print(stu1.name)
    # print(stu1.age)
    # print(stu1.gender)
    # print(tea1.__dict__)
    

    二、继承实现原理

    1 继承顺序

    在Java和C#中子类只能继承一个父类,而Python中子类可以同时继承多个父类,如A(B,C,D)

    如果继承关系为非菱形结构,则会按照先找B这一条分支,然后再找C这一条分支,最后找D这一条分支的顺序直到找到我们想要的属性

    如果继承关系为菱形结构,那么属性的查找方式有两种,分别是:深度优先和广度优先

    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如何实现的继承)

    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'>]
    

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

    三、super()

    调用super()会得到一个特殊的对象,该对象专门用来引用父类的属性,且严格按照MRO规定的顺序向后查找

    class People:
        school = "虹桥校区"
    
        def __init__(self,name,age,gender):
            self.name = name
            self.age = age
            self.gender = gender
    
    class Teacher(People):
        #            空对象,'egon',18,"male",10
        def __init__(self,name,age,gender,level):
            # People.__init__(self,name,age,gender)
            super(Teacher,self).__init__(name,age,gender)
    
            self.level = level
    
        def score(self):
            print("%s 正在为学生打分" %self.name)
    
    
    tea1 = Teacher('egon',18,"male",10)  # 空对象,'egon',18,"male",10
    print(tea1.__dict__)
    
    super()是依赖于继承的,并且即使没有直接继承关系,super()仍然会按照MRO继续往后查找
    

    super()案例:

    >>> #A没有继承B
    ... class A:
    ...     def test(self):
    ...         super().test()
    ... 
    >>> class B:
    ...     def test(self):
    ...         print('from B')
    ... 
    >>> class C(A,B):
    ...     pass
    ... 
    >>> C.mro() # 在代码层面A并不是B的子类,但从MRO列表来看,属性查找时,就是按照顺序C->A->B->object,B就相当于A的“父类”
    [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>,<class ‘object'>]
    >>> obj=C()
    >>> obj.test() # 属性查找的发起者是类C的对象obj,所以中途发生的属性查找都是参照C.mro()
    from B
    

    四、多继承的代码规范

    Pyton Mixins机制

    一个子类可以同时继承多个父类,这样的设计常被人诟病,一来它有可能导致可恶的菱形问题,二来在人的世界观里继承应该是个”is-a”关系。 比如轿车类之所以可以继承交通工具类,是因为基于人的世界观,我们可以说:轿车是一个(“is-a”)交通工具,而在人的世界观里,一个物品不可能是多种不同的东西,因此多重继承在人的世界观里是说不通的,它仅仅只是代码层面的逻辑。不过有没有这种情况,一个类的确是需要继承多个类呢?

    答案是有,我们还是拿交通工具来举例子:

    民航飞机、直升飞机、轿车都是一个(is-a)交通工具,前两者都有一个功能是飞行fly,但是轿车没有,所以如下所示我们把飞行功能放到交通工具这个父类中是不合理的,加上mixin飞的功能:

    class Vehicle:
        pass
    
    class FlyableMixin:   #加上飞行功能
        def fly(self):
            print('flying')
    
    class CivilAircraft(FlyableMixin,Vehicle):  #民航飞机,加 飞的功能放在父类的左边
        pass
    
    class Helicopter(FlyableMixin,Vehicle):  # 直升飞机,加上飞的功能
        pass
    
    class Car(Vehicle): #汽车
        pass
    

    五、组合

    在一个类中以另外一个类的对象作为数据属性,称为类的组合。组合与继承都是用来解决代码的重用性问题。不同的是:继承是一种“是”的关系,比如老师是人、学生是人,当类之间有很多相同的之处,应该使用继承;而组合则是一种“有”的关系,比如老师有生日,老师有多门课程,当类之间有显著不同,并且较小的类是较大的类所需要的组件时,应该使用组合

    简述--组合: 一个对象的属性值是指向另外一个类的对象

    class People:
        school = "虹桥校区"
    
        def __init__(self,name,age,gender):
            self.name = name
            self.age = age
            self.gender = gender
    
    class Student(People):
        def choose(self):
            print("%s 选课成功" %self.name)
    
    class Teacher(People):
        #            空对象,'egon',18,"male",10
        def __init__(self,name,age,gender,level):
            People.__init__(self,name,age,gender)
    
            self.level = level
    
        def score(self):
            print("%s 正在为学生打分" %self.name)
    
    class Course:
        def __init__(self,name,price,period):
            self.name = name
            self.price = price
            self.period =period
    
        def tell(self):
            print('课程信息<%s:%s:%s>' %(self.name,self.price,self.period))
    
    python = Course("python全栈开发",19800,"6mons")
    linux = Course("linux",19000,"5mons")
    
    stu1 = Student("jack",18,"male")
    stu2 = Student("tom",19,"male")
    stu3 = Student('lili',29,"female")
    
    
    tea1 = Teacher('egon',18,"male",10)  # 空对象,'egon',18,"male",10
    tea2 = Teacher('lxx',38,"male",3)
    
    
    stu1.courses = []
    stu1.courses.append(python)
    stu1.courses.append(linux)
    
    print(stu1.courses)
    for course_obj in stu1.courses:
        course_obj.tell()
    
  • 相关阅读:
    显示/隐藏Mac下的隐藏文件
    遍历指定文件下所有文件,删除指定后缀文件
    ssh公钥
    设置状态栏(statusbar)的样式
    Silverlight上传下载三种方法解析(三)
    Silverlight上传下载三种方式解析(二)
    Silverlight 上传下载之三种方式解析
    一个简单的存储过程代码生成器
    .net 程序发生了一个不可捕获的异常
    n取的r的组合数问题
  • 原文地址:https://www.cnblogs.com/caodan01/p/14268748.html
Copyright © 2020-2023  润新知