继承与派生

Posted hexianshen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了继承与派生相关的知识,希望对你有一定的参考价值。

一、继承

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的查找顺序:

新式类:广度优先

经典类:深度优先

查找顺序可以从下图看出

技术图片

 

 

 

 

 

 

 

以上是关于继承与派生的主要内容,如果未能解决你的问题,请参考以下文章

继承与派生

继承与派生

类的继承与派生

面向对象之继承与派生

类的继承与派生

继承与派生知识点