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

posted @ 2020-12-01 08:55  王寄鱼  阅读(166)  评论(0编辑  收藏  举报