06_03、面向对象的特征二:继承

一、继承

1. 什么是继承?

    继承就是新建类的一种方式,新建出来的类称为子类或者叫派生类,被继承的类称为父类或者基类
    子类可以遗产父类的属性

2. 为什么要用继承?

    类解决了对象与对象之间的代码冗余问题
    继承解决类与类之间的代码冗余问题

3. 怎么用继承?

    经典类:没有继承object类的子子孙孙类都是经典类
    新式类:继承了object类的子子孙孙类都是新式类
    '''只有在python2中才区分经典类和新式类,在python3中默认都是新式类'''

复制代码
class People():
    school = 'SH'
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

class Student(People):
    def __init__(self, name, age, gender, course=None):
        if course is None:
            course = []
        People.__init__(self, name, age, gender) # 指名道姓的调用
        self.course = course

    def choose_course(self):
        print('aaaa')


class Teacher(People):
    def __init__(self, name, age, gender, level):
        People.__init__(self, name, age, gender)
        self.level = level

    def score(self):
        print('打分')

stu = Student('tom', 19, 'male')
tea = Teacher('ly', 20 ,'female', 10)

print(stu.name)
print(stu.school)
print(tea.school)
复制代码

 二、单继承下的属性查找顺序

单继承下属性查找的顺序:

先在对象自己的名称空间中查找,再去产生对象的类中查找,再去继承的类中查找

例题1

复制代码
 1 class Foo:
 2     def f1(self):
 3         print('from Foo.f1')
 4 
 5     def f2(self):
 6         print('from Foo.f2')
 7         self.f1()
 8 
 9 
10 class Bar(Foo):
11     def f1(self):
12         print('from Bar.f1')
13 
14 
15 obj = Bar()
16 obj.f2()
17 
18 # from Foo.f2
19 # from Bar.f1
复制代码

例题2

复制代码
# 隐藏属性后的单继承条件下的属性查找
class
Foo: def __f1(self): # _Foo__f1() print('from Foo.f1') def f2(self): print('from Foo.f2') self.__f1() # _Foo__f1() class Bar(Foo): def __f1(self): # _Bar__f1() print('from Bar.f1') obj = Bar() obj.f2() # from Foo.f2 # from Foo.f1
复制代码

 

三、多继承下的属性查找顺序

经典类:深度优先查询
新式类:广度优先查询

 

 

 四、super和mro列表

1、super介绍

super是调用父类属性的一种方法,另一种方式是指名道姓的调用

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

注意在Python2中super的使用需要完整地写成super(自己的类名,self) ,而在python3中可以简写为super()

这两种方式的区别是:

  指名道姓调用是跟继承没有关系的

  super()是依赖于继承的,并且即使没有直接继承关系,super()仍然会按照MRO继续往后查找

2、MRO列表介绍

MRO列表就是一个简单的所有基类的线性顺序列表

为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。
而这个MRO列表的构造是通过一个C3线性化算法来实现的。

它实际上就是合并所有父类的MRO列表并遵循如下三条准则:
1.子类会先于父类被检查
2.多个父类会根据它们在列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类

复制代码
class People():  # 父类
    school = 'SH'

    # 自定义对象属性
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender


class Student(People):  # 子类
    # 自定义对象属性
    def __init__(self, name, age, gender, course=None):
        if course is None:
            course = []

        # 调用父类方式一:通过people指名道姓的调用
        # People.__init__(self, name, age, gender)  # 指名道姓的调用

        # 调用父类方式二:通过super调用
        # super(Student, self) super方法,返回的是一个特殊的对象

        # 注意super在python2和python3中的不同用法
        # super(Student, self).__init__(name, age, gender)  # python2中的写法
        super().__init__(name, age, gender)  # python3中的写法
        self.course = course

    def choose_course(self):  # 模拟选课方法
        print('aaaa')


stu = Student('tom', 19, 'male')  # 实例化对象
print(stu.school)
# SH
# 结果SH继承自父类people的school
复制代码

 五、组合

在一个类中以另外一个类的对象作为数据属性,称为类的组合。

组合与继承都是用来解决代码的重用性问题。

不同的是:

  继承是一种“是”的关系,比如老师是人、学生是人,当类之间有很多相同的之处,应该使用继承;

  而组合则是一种“有”的关系,比如老师有生日,老师有多门课程,

所以,当类之间有显著不同,并且较小的类是较大的类所需要的组件时,应该使用组合

复制代码
# 课程类
class Course:
    def __init__(self, name, period, price):
        self.name = name
        self.period = period
        self.price = price

    def tell_info(self):
        print('<%s %s %s>' % (self.name, self.period, self.price))


# 日期类
class Date:
    def __init__(self, year, mon, day):
        self.year = year
        self.mon = mon
        self.day = day

    def tell_birth(self):
        print('<%s-%s-%s>' % (self.year, self.mon, self.day))


# 人类
class People:
    school = '清华大学'

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


# Teacher类基于继承来重用People的代码,基于组合来重用Date类和Course类的代码
class Teacher(People):  # 老师是人
    def __init__(self, name, sex, age, title, year, mon, day):
        super().__init__(name, age, sex)  # 利用super继承父类People的属性
        self.birth = Date(year, mon, day)  # 老师有生日,组合
        self.courses = []  # 老师有课程,可以在实例化后,往该列表中添加Course类的对象,组合

    def teach(self):
        print('%s is teaching' % self.name)


python = Course('python', '3mons', 3000.0)  # 实例化Course为python对象
linux = Course('linux', '5mons', 5000.0)  # 实例化Course为linux对象
teacher1 = Teacher('lili', 'female', 28, '博士生导师', 1990, 3, 23)
# 实例化Teacher为teacher1对象


# teacher1有两门课程
teacher1.courses.append(python)
teacher1.courses.append(linux)

# 重用Date类的功能
teacher1.birth.tell_birth()

# 重用Course类的功能
for obj in teacher1.courses:
    obj.tell_info()
复制代码

 

posted @   三三得九86  阅读(47)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示