继承与派生

一、继承

1.什么是继承

继承是一种新建类的方式,新建的类称之为子类或派生类,继承的父类称之为基类或超类。

在python中,一个子类可以继承多个父类

在其他语言中,一个子类只能继承一个父类

2.继承的作用

减少代码的冗余

3.继承的实现

先确认谁是父类,先抽象,再继承;谁是子类

 1 # 父类
 2 class Father1:
 3     x = 1
 4     pass
 5 
 6 class Father2:
 7     pass
 8 
 9 class Father3:
10     pass
11 
12 
13 # 子类
14 class Sub(Father1):
15     pass
16 
17 # 子类查看父类__bases__
18 print(Sub.__bases__)
19 # (<class '__main__.Father1'>,)
20 print(Sub.x)
21 # 1
 1 # 问题: 代码冗余
 2 # 老师类
 3 class OldboyTeacher:
 4     school = 'oldboy'
 5     country = 'China'
 6 
 7     def __init__(self, name, age, sex):
 8         self.name = name
 9         self.age = age
10         self.sex = sex
11 
12     # 老师修改分数
13     def change_score(self):
14         print(f'老师 {self.name} 正在修改分数...')
15 
16 
17 # 学生类
18 class OldboyStudent:
19     school = 'oldboy'
20     country = 'China'
21 
22     def __init__(self, name, age, sex):
23         self.name = name
24         self.age = age
25         self.sex = sex
26 
27     # 学生选择课程
28     def choose_course(self):
29         print(f'学生 {self.name} 正在选择课程...')
30 
31 
32 stu1 = OldboyStudent('YJG', 50, 'female')
33 print(stu1.school, stu1.name, stu1.age, stu1.sex)
34 
35 tea1 = OldboyTeacher('tank', 17, 'male')
36 print(tea1.school, tea1.name, tea1.age, tea1.sex)

解决代码冗余

 1 class People:
 2     school = 'oldboy'
 3     country = 'China'
 4 
 5     def __init__(self, name, age, sex):
 6         self.name = name
 7         self.age = age
 8         self.sex = sex
 9 
10 class Student(People):
11     # school = 'oldboy'
12     # country = 'China'
13 
14     # def __init__(self, name, age, sex):
15     #     self.name = name
16     #     self.age = age
17     #     self.sex = sex
18     def func(self):
19         print('from student')
20 
21 class Teacher(People):
22     # school = 'oldboy'
23     # country = 'China'
24 
25     # def __init__(self, name, age, sex):
26     #     self.name = name
27     #     self.age = age
28     #     self.sex = sex
29     def func(self):
30         print('from teacher')
31 
32 
33 s1 = Student('张三', 23, '')
34 t1 = Teacher('李四', 25, '')
35 
36 print(s1.name, s1.age, s1.sex, s1.school)
37 print(t1.name, t1.age, t1.sex, t1.school)

4.继承的查找

注意:程序的执行顺序是由上到下,父类必须定义在子类的上方

在继承背景下,对象属性的查找顺序:
  1.先从对象自己的名称空间中查找
  2.对象中没有,从子类的名称空间中查找。
  3.子类中没有, 从父类的名称空间中查找,若父类没有,则会报错!

 1 # 父类
 2 class Father:
 3     x = 10
 4     pass
 5 # 子类
 6 class Sub(Father):
 7     x = 20
 8     pass
 9 sub_obj = Sub()
10 
11 # 此方法并未修改调用对象类的值,而是给调用产生的对象增加一个属性
12 print('对象的名称空间:', sub_obj.__dict__)
13 sub_obj.x = 30
14 print(sub_obj.x)      # 30
15 print('父类的名称空间:', Father.__dict__)
16 print('子类的名称空间:', Sub.__dict__)
17 print('对象的名称空间:', sub_obj.__dict__)
 1 # 父类
 2 class Father:
 3     x = 10
 4     pass
 5 # 子类
 6 class Sub(Father):
 7     x = 20
 8     pass
 9 sub_obj = Sub()
10 # sub_obj.x = 30
11 print(sub_obj.x)        # 20
12 
13 
14 # 父类
15 class Father:
16     x = 10
17     pass
18 # 子类
19 class Sub(Father):
20     # x = 20
21     pass
22 sub_obj = Sub()
23 # sub_obj.x = 30
24 print(sub_obj.x)        # 10
25 
26 
27 # 父类
28 class Father:
29     # x = 10
30     pass
31 # 子类
32 class Sub(Father):
33     # x = 20
34     pass
35 sub_obj = Sub()
36 # sub_obj.x = 30
37 print(sub_obj.x)        # 报错

二、派生

1.什么是派生

指的是子类继承父类的属性与方法,并且派生出自己独有的属性与方法。
若子类中的方法名与父类的相同,优先用子类的。

2.派生的实现

子类继承父类,派生出自己的属性与方法,并且重用父类的属性与方法。

 1 # 父类
 2 class Foo:
 3     def f1(self):
 4         print('from Foo.f1')
 5     def f2(self):
 6         print('from Foo.f2')
 7         self.f1()
 8 class Bar(Foo):
 9     # 重写
10     def f1(self):
11         print('from Bar.f1')
12 
13     def func(self):
14         print('from Bar.func')
15 bar_obj = Bar()
16 
17 bar_obj.f1()
18 # from Bar.f1
19 bar_obj.func()
20 # from Bar.func
21 bar_obj.f2()
22 """
23 输出结果:
24     from Foo.f2
25     from Bar.f1
26 """

问题:子类重写父类的__init__导致代码更加冗余

class OldboyPeople:
    school = 'oldboy'

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


class OldboyTeacher(OldboyPeople):

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

    def change_score(self):
        print(f'老师 {self.name} 修改分数...')


class OldboyStudent(OldboyPeople):

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

    def choose_course(self):
        print(f'学生 {self.name} 选择课程...')


tea1 = OldboyTeacher('张三', 23, 'male', 1500)
stu1 = OldboyStudent('李四', 28, 'male', '凤姐')
print(tea1.name, tea1.age, tea1.sex, tea1.sal)
print(stu1.name, stu1.age, stu1.sex, stu1.girl)

解决问题: 子类重用父类的属性,并派生出新的属性。
两种方式:
  1.直接引用父类的__init__为其传参,并添加子类的属性。
  2.通过super来指向父类的属性。
    - super()是一个特殊的类,调用super得到一个对象,该对象指向父类的名称空间。

注意: 使用哪一种都可以,但不能两种方式混合使用。

 1 # 方法一:
 2 class OldboyPeople:
 3     school = 'oldboy'
 4 
 5     def __init__(self, name, age, sex):
 6         self.name = name
 7         self.age = age
 8         self.sex = sex
 9 
10 
11 class OldboyTeacher(OldboyPeople):
12 
13     def __init__(self, name, age, sex, sal):
14         OldboyPeople.__init__(self, name, age, sex)
15         self.sal = sal
16 
17     #     self.name = name
18     #     self.age = age
19     #     self.sex = sex
20     #     self.sal = sal
21     def change_score(self):
22         print(f'老师 {self.name} 修改分数...')
23 
24 
25 class OldboyStudent(OldboyPeople):
26 
27     def __init__(self, name, age, sex, girl):
28         OldboyPeople.__init__(self, name, age, sex)
29         self.girl = girl
30         # self.name = name
31         # self.age = age
32         # self.sex = sex
33         # self.girl = girl
34 
35     def choose_course(self):
36         print(f'学生 {self.name} 选择课程...')
37 
38 
39 tea1 = OldboyTeacher('张三', 23, 'male', 1500)
40 stu1 = OldboyStudent('李四', 28, 'male', '凤姐')
41 print(tea1.name, tea1.age, tea1.sex, tea1.sal)
42 print(stu1.name, stu1.age, stu1.sex, stu1.girl)
 1 # 方法二
 2 class OldboyPeople:
 3     school = 'oldboy'
 4 
 5     def __init__(self, name, age, sex):
 6         self.name = name
 7         self.age = age
 8         self.sex = sex
 9 
10 
11 class OldboyTeacher(OldboyPeople):
12 
13     def __init__(self, name, age, sex, sal):
14         super().__init__(name, age, sex)
15         # self.name = name
16         # self.age = age
17         # self.sex = sex
18         self.sal = sal
19 
20     def change_score(self):
21         print(f'老师 {self.name} 修改分数...')
22 
23 
24 class OldboyStudent(OldboyPeople):
25 
26     def __init__(self, name, age, sex, girl):
27         super().__init__(name, age, sex)
28         # self.name = name
29         # self.age = age
30         # self.sex = sex
31         self.girl = girl
32 
33     def choose_course(self):
34         print(f'学生 {self.name} 选择课程...')
35 
36 
37 tea1 = OldboyTeacher('张三', 23, 'male', 1500)
38 stu1 = OldboyStudent('李四', 28, 'male', '凤姐')
39 print(tea1.name, tea1.age, tea1.sex, tea1.sal)
40 print(stu1.name, stu1.age, stu1.sex, stu1.girl)

3、新式类与经典类

- 新式类:
  1.凡是继承object的类或子孙类都是新式类。
  2.在python3中所有的类都默认继承object。

- 经典类:
  1.在python2中才会有经典类与新式类之分。
  2.在python2中,凡是没有继承object的类,都是经典类。

mro的查找顺序:

新式类:广度优先

经典类:深度优先

查找顺序可以从下图看出

 

 

 

 

 

 

 

posted @ 2019-11-26 18:44  treeter  阅读(429)  评论(0编辑  收藏  举报