22、继承与派生

一、继承的认知

1、什么是继承

继承是一种新建子类的方式,新建的类称之为子类/派生类,被继承的称之为父类/基类,子类会遗传父类的属性

2、为何要用继承

类是解决对象之间冗余问题的,继承可以解决类与类之间的冗余问题

3、如何继承

在python中支持多继承

在python3中如果一个类没有继承任何父类,那么默认继承object类

但凡是继承了object类的子类,以及该子类的子子孙孙类都能用到object内的功能,称之为新式类
没有继承了object类的子类,以及该子类的子子孙孙类都能用不到object内的功能,称之为经典类

ps:只有在python2中才区分经典类与新式类,python3中都是新式类

4、继承的语法

class Parent1:  # 定义父类
    pass


class Parent1:  # 定义父类
    pass


class Sub1(Parent1):  # 单继承
    pass


class Sub2(Parent1, Parent2):  # 多继承,用逗号分隔开
    pass

通过类的内置属性__bases__可以查看类继承的所有父类

print(Sub1.__bases__)
print(Sub2.__bases__)

# 运行结果
(<class '__main__.Parent1'>,)
(<class '__main__.Parent1'>, <class '__main__.Parent2'>)

二、继承与抽象

继承描述的是子类与父类之间的关系,是一种什么是什么的关系。要找出这种关系,必须先抽象再继承

抽象即抽取类似或者说比较像的部分。

1、抽象

1.将奥巴马和梅西这俩对象比较像的部分抽取成类;

2.将人,猪,狗这三个类比较像的部分抽取成父类。

抽象最主要的作用是划分类别(可以隔离关注点,降低复杂度

img

2、继承

是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构。

img

三、继承与重(chóng)用性

1、子类如何重用父类的功能

子类重用父类功能 就叫派生

# 定义一个学生类
class Student():
    school = '加里敦大学'

    def __init__(self, name, age, gender, courses=None):
        if courses is None:
            courses = []
        # 学生信息
        self.name = name
        self.age = age
        self.gender = gender
        self.courses = courses

    # 学生选课的功能
    def choose_course(self, course):
        self.courses.append(course)
        print('学生%s 选课%s 成功' % (self.name, self.courses))


# 定义一个老师类
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, stu_obj, num):
        stu_obj.num = num
        print('老师%s 为学生%s 打分%s' % (self.name, self.stu_obj.name, num))


stu1_obj = Student('poco', 18, 'male')
tea1_obj = Teacher('egon', 38, 'male', 10)

print(stu1_obj.__dict__)
print(tea1_obj.__dict__)

现在我们定义了一个学生类和一个老师类,但你有没有发现,其实很多地方他们的功能好像都有点重复,像学校、姓名、年龄等......这时候我们应该定义一个父类来存放他们相同功能的地方

方式一:指名道姓

定义一个名为People的父类,把相同部分的功能放入了这个类中,在子类调用父类的__init__方法

class People:  # 定义父类
    school = '加里敦大学'

    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender


# 定义一个学生类
class Student(People):

    def __init__(self, name, age, gender, courses=None):
        People.__init__(self, name, age, gender)  # 调用父类的功能
        if courses is None:
            courses = []
        # 学生信息
        # self.name = name
        # self.age = age
        # self.gender = gender
        self.courses = courses

    # 学生选课的功能
    def choose_course(self, course):
        self.courses.append(course)
        print('学生%s 选课%s 成功' % (self.name, self.courses))


# 定义一个老师类
class Teacher(People):

    def __init__(self, name, age, gender, level):
        People.__init__(self, name, age, gender)  # 调用父类
        # # 老师信息
        # self.name = name
        # self.age = age
        # self.gender = gender
        self.level = level

    # 老师打分的功能
    def score(self, stu_obj, num):
        stu_obj.num = num
        print('老师%s 为学生%s 打分%s' % (self.name, self.stu_obj.name, num))


stu1_obj = Student('poco', 18, 'male')
tea1_obj = Teacher('egon', 38, 'male', 10)

print(stu1_obj.__dict__)
print(tea1_obj.__dict__)

方式二:super()

class People:  # 定义父类
    school = '加里敦大学'

    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender


class Student(People):
    def __init__(self, name, age, gender, courses=None):
        super().__init__(name, age, gender)  # super()方法调用父类功能
        if courses is None:
            courses = []
        self.courses = courses

    def choose_course(self, course):
        self.courses.append(course)
        print('学生%s 选课%s 成功' % (self.name, self.courses))


class Teacher(People):

    def __init__(self, name, age, gender, level):
        super().__init__(name, age, gender)
        self.level = level

    def score(self, stu_obj, num):
        stu_obj.num = num
        print('老师%s 为学生%s 打分%s' % (self.name, self.stu_obj.name, num))


stu1_obj = Student('poco', 18, 'male')
stu1_teal = Teacher('egon', 38, 'male', 10)

print(stu1_obj.__dict__)
print(stu1_teal.__dict__)

关于在子类中重用父类功能的这两种方式,使用任何一种都可以,但是在最新的代码中还是推荐使用super()

2、菱形继承与非菱形继承

之前我们介绍过 对象在查找属性时,先从对象自己开始找,如果没有则去 类中找,如果再没有,再去父类中找。那我们知道,Python是支持多继承的,如果是多继承的背景下,那又该怎么进行查找呢.

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

如果继承关系为菱形结构,那么属性的查找方式有两种,分别是:深度优先和广度优先,而在Python3中所有的类都是新式类,所以查找属性不存在时,会按照广度优先的方式查找,具体如下图

img

class D():
    def test(self):
        print('D')

class C():
    def test(self):
        print('C')

class B():
    def test(self):
        print('B')


class A(B,C,D):
    def test(self):
        print('A')
obj = A()
obj.test()
# 记不住也没有关系,我们可以用mro可以查看属性查找的顺序
print(A.mro())

四、Mixins机制

Mixins机制其实是一种语法的规范,简单来说Mixins机制指的是子类混合(mixin)不同类的功能,而这些类采用统一的命名规范(例如Mixin后缀),以此标识这个类是作为功能添加到子类中,而不是作为父类,在类名后面加上Mixin就行,通常放在类的参数的前面

比如说下面的代码,直升飞机和民航飞机都会飞,但汽车不会,所以定义一个飞行的类,作为一个从属的类来使用,所以将飞行的类名后添加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
posted @ 2021-04-15 21:15  黑影Poco  阅读(121)  评论(0)    收藏  举报