zoukankan      html  css  js  c++  java
  • Python-继承

    一、继承介绍

    继承

    继承是一种新建类的方式,新建的类称之为子类,被继承的类称为父类,也称为基类与超类

    为何要用继承:

    子类会遗传父类的属性(与方法),所以继承是解决类与类之间代码冗余的问题

    还记得我们为什么会定义出类吗,我们学习的编程方法叫做面向对象编程,而不是面向类编程,那前几天开始学习时我们的类是为什么创建出来的呢?
    当我们创建对象时,发现很多对象都会有相同的特征,如名字,性别,年龄等,每创建一个对象我们就要写重复代码,所以类是为了减少对象与对象之间代码冗余的问题

    如何继承

    class Parent1:
        pass
    
    class Parent2:
        pass
    
    class Sub1(Parent1):
        pass
    
    class Sub2(Parent1,Parent2):
        pass
    
    print(Sub1.__bases__)  #利用__bases__可以查看一个类继承了哪些类
    print(Sub2.__bases__)
    ----------------------
    (<class '__main__.Parent1'>,)
    (<class '__main__.Parent1'>, <class '__main__.Parent2'>)
    
    
    
    # 继承案列:
    class MIT:
        school = "MIT"
    
    class Student(MIT):
        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)
    
    stu1=Student("yang",18,'male',1001,"python")
    
    print(stu1.school)
    -----------------
    MIT
    

    二、继承与抽象

    名字很高大上,其实就是为了帮助我们理解为什么要有父类。抽象的意思,就是我们从不同的对象总结相同特点,创建一个类,之后再根据类的相同特征再找出一个父类,如人可以是一个类,猫可以是一个类,狗可以是一个类,我们还可以根据这三个类总结一个动物类。这个过程就是抽象的过程。
    而当我们根据以上的关系根据三个类实例化出对象,那么动物类就是人,猫,狗的父类。

    三、属性查找

    有了继承关系,对象在查找属性时,先从对象自己的__dict__中找,如果没有则去自己的类中找,然后再去父类中找。

    因为属性查找的顺序,所以当子类与父类都有同一个方法名(但是功能不同)时,总是会优先查找子类中的方法,就产生了一个覆盖的效果。
    若父类不想让子类调用自己的方法,可以利用隐藏属性,加入双下划线,这就表示这个方法只能在本类中调用

    # 在子类派生的新方法中重用父类的功能
    # 方式一:指名道姓地调用某一个类的函数
    # 特点:不依赖于继承关系
    
    class MITPeople:
        school = "MIT"
    
        def __init__(self,name,age,gender):
            self.name = name
            self.age = age
            self.gender = gender
    
        def f1(self):
            print('11111')
    
    class Student(MITPeople):
    
        def __init__(self,name,age,gender,stu_id,course):
            MITPeople.__init__(self,name,age,gender)
            self.stu_id = stu_id
            self.course = course
    
        def choose(self):
            print('%s 正在选课' %self.name)
    
        def f1(self):
            MITPeople.f1(self)
            print("22222")
    
    class Teacher(MITPeople):
        def score(self,stu,num):
            stu.num = num
    
    
    stu1=Student("yang",18,'male',1001,"python")
    
    stu1.f1()
    -----------------
    11111
    22222
    

    四、继承的实现原理

    新式类:继承了Object类的子类以及他的所有子类,都称为新式类
    经典类:没有继承Object类的任何类都称为经典类
    在python3中,做了处理,所有的类都是新式类。即如果你在定义一个类的时候,没有继承其他类,python3会默认帮你继承Object类,在python2中并无此处理,所以python2中既有经典类也有新式类。
    若你写的类想要兼容python2与python3,只要在定义类时,继承Object就可以了

    五、菱形问题

    菱形问题:一个子类继承的多条分支最终汇聚到一个不是Object的类,注意,菱形问题不是一个好事情,在你的项目中一定要尽可能的避免这个问题
    如果继承关系为菱形结构,即子类的父类最后继承了同一个类且这个类不是object,那么属性的查找方式有两种:
    经典类:深度优先
    新式类:广度优先
    深度优先演示图:
    img
    广度优先演示图:
    img

    C3算法与mro()方法介绍(了解即可)
    python到底是如何实现继承的,对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表,如:

    print(A.mro())  # A.__mro__
    ---------------------------
    [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class '__main__.G'>, <class 'object'>]
    
    for i in A.mro():
        print(i)
    ---------------------------
    <class '__main__.A'>
    <class '__main__.B'>
    <class '__main__.E'>
    <class '__main__.C'>
    <class '__main__.F'>
    <class '__main__.D'>
    <class '__main__.G'>
    <class 'object'>
    

    六、Pyton Mixins机制

    名字很高级,说白了就是把只属于自己的类方法从大的类里提取出来,然后多继承。通过下面的例子很容易看懂。

    首先这不是一个语法,而更像是一个python程序员之间的约定
    Python既然设计了可以多继承,那么多继承一定有他便利的地方,最了然的就是我们可以继承多个类,减少代码冗余。但是多继承又容易产生菱形问题,并且和我们以往的继承思想有所不同。
    人的世界观里继承应该是个”is-a”关系。 比如轿车类之所以可以继承交通工具类,是因为基于人的世界观,我们可以说:轿车是一个(“is-a”)交通工具,而在人的世界观里,一个物品不可能是多种不同的东西,因此多重继承在人的世界观里是说不通的。
    但是在我们的程序设计中,又是可能会出现一个对象却是需要继承多个类。如下例子:

    '''
    民航飞机、直升飞机、轿车都是一个(is-a)交通工具,前两者都有一个功能
    是飞行fly,但是轿车没有,所以如下所示我们把飞行功能放到交通工具这个
    父类中是不合理的
    '''
    class Vehicle:  # 交通工具
        def fly(self):
            # 飞行功能相应的代码        
            print("I am flying")
    
    
    class CivilAircraft(Vehicle):  # 民航飞机
        pass
    
    
    class Helicopter(Vehicle):  # 直升飞机
        pass
    
    
    class Car(Vehicle):  # 汽车并不会飞,但按照上述继承关系,汽车也能飞了
        pass
    

    但是如果民航飞机和直升机都各自写自己的飞行fly方法,又违背了代码尽可能重用的原则(如果以后飞行工具越来越多,那会重复代码将会越来越多)。
    怎么办???为了尽可能地重用代码,那就只好在定义出一个飞行器的类,然后让民航飞机和直升飞机同时继承交通工具以及飞行器两个父类,这样就出现了多重继承。这时又违背了继承必须是”is-a”关系。这个难题该怎么解决?

    Python提供了Mixins机制,简单来说Mixins机制指的是子类混合(mixin)不同类的功能,而这些类采用统一的命名规范(例如Mixin后缀),以此标识这些类只是用来混合功能的,并不是用来标识子类的从属"is-a"关系的,所以Mixins机制本质仍是多继承,但同样遵守”is-a”关系,如下

    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类,也照样可以工作,就是缺少了某个功能。(比如飞机照样可以载客,就是不能飞了)

  • 相关阅读:
    mysql 数据库引擎
    dubbo 微服务
    spring 属性文件加载接口---PropertySourceLoader
    Shiro架构
    HTTP状态码
    Shiro 修改权限,刷新权限
    Consul 架构(译)
    Java EE平台介绍(译)
    Java SPI机制
    Otb_000_ElementUI 的 Drawer组件无法上下滚动没有滚动条
  • 原文地址:https://www.cnblogs.com/chiyun/p/14066140.html
Copyright © 2011-2022 走看看