继承 inheritance 和 派生 derived
什么是继承 / 派生
1.继承是从已有的类中派生出新的类,新类具有原类的数据属性和行为,并能扩展新的行为
2.派生类就是从一个已有的类中衍生出新的类,在新类的基础上添加新的属性和行为
为什么继承 / 派生
继承的目的是延续旧类的功能
派生的目的是在旧类的基础上改变原有的功能
名词:
基类(base class)/超类(super class)/父类(father class)
派生类(derived class)/子类(child class)
单继承
语法:
class 类名(基类名):
语句块
说明:
单继承是指派生类由一个基类衍生出来新类
示例:
#此示例示意单继承的定义方法和用法
class Human:
def say(self,what):
print('说',what)
def walk(self,distance):
print('走了',distance,'公里')
class Student(Human):
def study(self,subject):
print('正在学习',subject)
class Teacher(Student):
def teach(self,what):
print('说',what)
h1 = Human()
h1.say('今天天气真好') #说 今天天气真好
h1.walk(5) #走了 5 公里
s1 = Student()
s1.walk(4) #走了 4 公里
s1.say('感觉有点累') #说 感觉有点累
s1.study('python') #正在学习 python
t1 = Teacher()
t1.teach('面向对象') #说 面向对象
t1.walk(6) #走了 6 公里
t1.say('太累了,今天吃麻辣香锅') #说 太累了,今天吃麻辣香锅
t1.study('英雄联盟 ') #正在学习 英雄联盟
多继承 multipe inhereitance
多继承是指一个子类继承来自两个或两个以上的基类
语法:
class 类名(基类名1,基类名2,.......)
说明:
一个子类同时继承自多个父类,父类中的方法可以同时被继承下来
如果两个父类中有同名的方法,而在子类中又没有付给此方法时,调用结果难以确定
示例:
#multiple_inherit.py
class Car:
def run(self,speed):
print('汽车以',speed,'公里/小时的速度行驶')
class Plane:
'''飞机类'''
def fly(self,height):
print('飞机以海拔',height,'米的高度飞行')
class PlaneCar(Car,Plane):
'''PlaneCar类同时继承自汽车类和飞机类'''
p = PlaneCar() #创建一个飞行汽车对象
p.fly(110000)
p.run(100)
多继承的问题(缺陷)
标识符冲突问题
(要谨慎使用多继承)
示例:
#multiple_inherit2.py
小张写了一个类A
class A:
def m(self):
print('A.m()被调用')
#小李写了一个类 B
class B:
def m(self):
print("B.m()被调用")
小王感觉小李和小张写的两个类自己都能用
class AB(B,A):
pass
ab = AB()
ab.m()
多继承的MRO(Method Resolution Order)
python3的类的__mro__属性
作用:
用来记录类的方法查找顺序
示例:
# mro.py
class A: #4
def go(self):
print('A')
class B(A): #2
def go(self):
print('B')
super().go() #C
class C(A): #3
def go(self):
print('C')
class D(B,C): #1
def go(self):
print('D')
super().go()
d = D()
d.go()
继承派生机制的作用
1.可以将一些共用的功能加在基类中,实现代码的共享
2.在不改变基类的基础上改变原有的功能
练习:
list类里只有append向末尾加一个元素的方法,但没有向列表头部添加元素的方法
试想能否为列表在不改变原有功能的基础上添加一个inster_head(x)方法,此方法能在列表的前部添加元素
class Mylist(list):
def insert_head(self,x):
# self.reverse()
# self.append(x)
# self.reverse()
self.insert(0,x) #直接在最开始插入x
myl = Mylist(range(3,6))
print(myl) #[3.4.5]
myl.insert_head(2)
print(myl) #[2,3,4,5]
myl.append(6)
print(myl) #[2,3,4,5,6]
继承说明:
Python 3任何类型都直接或间接的继承object类
object类是一切类的超类
类的__base__属性:
__base__属性用来记录此类的基类
python内建的类详见:
>>>help(__builtins__)
覆盖 override
什么是覆盖
覆盖是指在继承关系的类中,子类中实现了与基类同名的方法,
在子类的实例调用该方法时,实际调用的是子类的覆盖版本,这种现象叫做覆盖
示例:
#此示例示意覆盖的含义及方法
class A:
def work(self):
print('A.work被调用')
class B(A):
'''B类继承子A类'''
def work(self):
print('B.work被调用')
b = B()
b.work() #B.work被调用
a = A()
a.work() #A.work被调用
# A.work(b) #A.work被调用
问题:
当覆盖发生时,子类对象如何调用父类中的被覆盖方法
调用方式:
基类名.方法名(实例,实际调用传参.....)
super函数
super(cls,obj)返回被绑定超类的实例(要求obj必须为cls类型的实例)
super() 返回被绑定超类的实例,等同于:super(__class__,实例方法的第一个参数,必须在方法内调用)
作用:
借助super()返回的实例间接调用父类的覆盖方法
示例;
>>> #此示例示意用super函数间接调用父类的
class A:
def work(self):
print('A.work被调用')
>>> class B(A):
'''B类继承子A类'''
def work(self):
print('B.work被调用')
def super_work(self):
#调用b类自己的work方法
self.work()
#调用父类的work
super(B,self).work()
super().work() #此种调用方式只能在实例方法内调用
>>> b = B()
>>> b.work()
B.work被调用
>>> super(B,b).work()
A.work被调用
>>> b.super_work()
B.work被调用
A.work被调用
A.work被调用
>>>
显示调用基类的初始化方法
当子类中实现了__init__方法,基类的构造方法并不会被调用,此时需要显示调用
示例:
>>> #此示例示意显示调用初始化方法
>>> class Human:
def __init__(self,n,a):
self.name = n
self.age = a
print("Human类的初始化方法被调用...")
def infos(self):
print('姓名:',self.name)
print('年龄:',self.age)
>>> class Student(Human):
def __init__(self,n,a,s = 0):
super(Student,self).__init__(n,a)
self.score = s
print("Student的初始化方法被调用...")
def infos(self):
super().infos() #显示调用父类的方法
# print('姓名',self.name)
print("成绩",self.score)
>>> s1 = Student('张飞', 15, 80)
Human类的初始化方法被调用...
Student的初始化方法被调用...
>>> s1.infos()
姓名: 张飞
年龄: 15
成绩 80
>>>
调用基类初始化方法的另一种方法:
class Student(Human):
def __init__(self,n,a,s = 0):
Human.__init__(self,n,a)
self.score = s
print("Student的初始化方法被调用...")
def infos(self):
super().infos() #显示调用父类的方法
print("成绩",self.score)
>>> s1 = Student('张飞', 15, 80)
Human类的初始化方法被调用...
Student的初始化方法被调用...
>>> s1.infos()
姓名: 张飞
年龄: 15
成绩 80
>>>