python面向对象(继承与派生、同名方法覆盖以及覆盖的解决办法)

一、继承与派生 inheritance 和 derived
1.什么是继承或者派生
继承是从已有的类中派生出新的类,新类具有原类的数据属性和行为,并扩展新的能力
派生就是从一个已有的类衍生出来的新类,在原来的类的基础上添加新的属性或者方法

作用:
用继承派生机制,可以将一些共有功能加在基类上,实现代码复用
在不改变超类的代码的基础上,改变原有的功能

名词:
基类(base class)/超类(super class)/父类(father class):一个概念
派生类(derived class)/子类(child class)

2.单继承:

class 类名(父类名):
    语句块

示例:

class Human:   #人....
    def say(self,words):    #说话行为
        print("说了:",words)
    def walk(self,distance):#走路行为
        print("走了:",distance,"公里")

h1 = Human()
h1.say("今天天气真好")
h1.walk(50)

print("------------------------------------------------")
#创建一个学生类,多一个学习的行为
class Student(Human):
    def study(self,subject):
        print("今天学的科目是",subject)

s1 = Student()
s1.say("今天天气真好")  #直接调用父类的方法
s1.walk("100")
s1.study("物理")

执行结果:
说了: 今天天气真好
走了: 50 公里
------------------------------------------------
说了: 今天天气真好
走了: 100 公里
今天学的科目是 物理


#设计一个teacher类,要求包含学习和教学的行为
class teacher(Student):     #既继承了human也继承了student
    def teach(self,subject):
        print("我教书的科目是:",subject)

t = teacher()
t.say("good")
t.walk(199)
t.study("math")
t.teach("python")

执行结果:
说了: good
走了: 199 公里
今天学的科目是 math
我教书的科目是: python


注:
student对象找相应方法从自身开始,自下而上,找到Human类中的同名方法,将student类的对象传给对应的方法,即可。

练习:
我们知道内建模块中的list只有append向末尾添加元素的方法,但没有向列表首部添加的方法,能否设计一个类,实现Insert_head(n),在列表头插入元素

class mylist(list):
    def insert_head(self,element):
        self.insert(0,element)

l = mylist()

l.append(1)
l.append(2)
l.insert_head(9)
for x in l:
    print(x,end = ' ')
执行结果:
9 1 2 

继承说明:
任何类都可以直接或者间接的继承自object类

object类是一切类的超类

类内的__base__属性:
此属性来记录此类的基类是谁

见:help(builtins)

示例:

class Human:        #这里什么类都没有继承  默认是继承自object类
    def say(self,words):    #说话行为
        print("说了:",words)
    def walk(self,distance):#走路行为
        print("走了:",distance,"公里")
        
class Student(Human):
    def study(self,subject):
        print("今天学的科目是",subject)

 class teacher(Student):
     def teach(self,subject):
        print("我教书的科目是:",subject)
help(Human.__base__)
help(Student.__base__)
help(teacher.__base__)

执行结果:
class Human(builtins.object)
class Student(Human)
.....

二、覆盖(重写):override
什么是覆盖:
覆盖是指在有继承派生关系的类中,子类中实现了与基类同名的方法,在子类对象调用方法的时候,实际调用的是子类中的同名方法,这种现象叫覆盖
(同名就会发生覆盖,其实可以这样理解,同名的方法一般是自己创建的方法是最合适自己的,所以一定优先调用自己创建的方法了,自己有自己的想法 -_-)

class A:
    def work(self):
        print("A")

class B(A):
    def work(self):
        print("B")

b = B()
b.work()
#既然我自己定义了,肯定是父类的不太适合我,我肯定优先调用我自己,所以子类就把父类的方法覆盖掉了

问题:当覆盖发生时,如果子类非要调用父类的同名方法怎么办
有两种方法:
1.“指名道姓”的调用父类的方法
2.super()函数

super:
super(子类type,子类obj):把子类对象的类型当成父类的类型来调用方法
返回绑定超类的实例,要求obj必须是type类型实例
super()返回绑定超类的实例,等同于super(class,实例的第一个参数),且必须在方法内调用

方法1:

class A:
    def work(self):
        print("A")

class B(A):
    def work(self):
        print("B")

b = B()
A.work(b)    #指名道姓的要调用父类的方法,解释器能明白子类的意思

方法2:原本对象找方法是从自身向上找,super修改为从父类开始查找

class A:
    def work(self):
        print("A")

class B(A):
    def work(self):
        print("B")

#super函数来访问被覆盖掉的父类方法,
b = B()
b.work()
#优先从父类的方法开始查找
super(B,b).work()
执行结果:
B
A

示例:演示如何用super函数让子类显示调用父类的种被覆盖的函数

class A:
    def work(self):
        print("A")

class B(A):
    def work(self):
        print("B")

    def doworks(self):
        #self.work()  #当然是调用B的work,能执行到这里说明self是B类型
        super(B,self).work()#调用父类的work方法
        super().work() #调用父类的方法

b = B()
b.work()
b.doworks()
执行结果:
B
A
A

说明:
当子类种实现了__init__方法后,父类的__init__方法将被覆盖,即不再会主动的调用父类的__init__方法,会引起父类的属性得不到初始化,此时我们要显式的调用父类的初始化函数。

示例:

class Human:
    def __init__(self,n,a):
        self.name = n
        self.age = a
        print("Human种的init函数被调用")

    def show_info(self):
        print("姓名:",self.name)
        print("年龄:",self.age)

class Student(Human):
    def __init__(self,n,a,s = 0):
        super().__init__(n,a)   #显式调用父类的初始化方法
        #super(Human,self)._init_(n,a)  #也可以这样显式的调用
        self.score = s
        print("Student中的init函数被调用")

    def show_info(self):
        super().show_info()    #调用父类中的show_info
        print("成绩为:",self.score)

#上述子类种init和show_info函数把父类的所有同名函数都给覆盖了
#导致父类的初始化函数不能被执行,
#也就是说子类对象中的父类部分没有初始化,所以我们需要在子类的初始化中显式的调用父类的初始化函数

s1 = Student("安琪拉",500,99)

执行结果:
Human种的init函数被调用
Student中的init函数被调用

猜你喜欢

转载自blog.csdn.net/KingOfMyHeart/article/details/89146075