目录
❤ 什么是继承
❤ 派生和继承
❤ 单继承
❤ 多继承
❤ MRO[方法搜索顺序](多继承顺序)
❤ 新式类和旧式(经典)类
❤ 什么是继承
通过继承基类来得到基类的功能
所以我们把被继承的类称作父类或基类,继承者被称作子类
可以使代码进行重用
子类继承了其父类的所有属性和方法,同时还可以定义自己的属性和方法。
❤ 派生和继承
“派生”和“继承”是一个意思,只是观察角度不同而已。换句话话,继承是相对子类来说的,即子类继承自父类;而派生是相对于父类来说的,即父类派生出子类。
class People:
def __init__(self):
self.name = People
def say(self):
print("People类",self.name)
class Animal:
def __init__(self):
self.name = Animal
def say(self):
print("Animal类",self.name)
#People中的 name 属性和 say()中的 name 会遮蔽 Animal 类中的 name
class Person(People, Animal):
pass
zhangsan = Person()
zhangsan.name = "张三"
zhangsan.say()
输出:
People类 张三
可以看到,当 Person 同时继承 People 类和 Animal 类时,People 类在前,因此如果 People 和 Animal 拥有同名的类方法,实际调用的是 People 类中的。
在Python中,继承可以分为单继承、多继承和多层继承。
❤ 单继承:子类只继承一个父类
继承语法:
class
类名(父类名):
pass
子类继承自父类,可以享受父类中已经封装好的方法,不需要再次定义
子类中应该根据职责,封装子类特有的属性和方法。
继承的传递性:
子类拥有父类以及父类的父类中封装的所有属性和方法。
❤ 多继承
子类可以拥有多个父类,并且具有所有父类的属性和方法
class
子类名(父类名
1
,父类名
2.
..)
pass
案列1:
class A:
def test(self):
print("A --- test方法")
def demo(self):
print("A --- demo方法")
class B:
def demo(self):
print("B --- demo方法")
def test(self):
print("B --- test方法")
class C(B, A):
pass
# 创建子类对象
c = C()
c.test()
c.demo()
print(C.__mro__)
输出:
B --- test方法
B --- demo方法
(<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
这里补充一个知识:
❤ MRO[方法搜索顺序](多继承顺序)
所谓方法搜索顺序,就是让某个对象调用某个方法时,python的解释器是按照什么样的顺序在创建这个对象的类,以及父类之间搜索方法的。
-
在python中针对类提供了一个内置属性 mro ,可以查看方法搜索顺序。(mro前后两个下划线)
-
MRO是 method resolution order缩写,主要用于在多继承时判断方法、属性的调用路径。
案列1的运行过程:
在控制台输出了一个元组。当让C类创建的对象方法时,Python解释器会首先在C类中查找有没有这个方法,如果有就会直接执行,而不会向后搜索。如果没有找到这个方法,就会按照元组的顺序从左向右查找第二个类中是否有这个方法,如果在B类中找到就会直接执行也不会向后搜索。如果没有找到就会按照从左向右的顺序继续向下寻找,在第三个类中A类中继续查找有没有提供这个方法,如果找到就执行,如果没有找到继续向后寻找下一个类object类,如果还没找到程序就会报错。(在python3中object是所有类的基类,也就是只要定义一个类,这个类的最终基类都是object类,简单来讲object是python中所有类的祖宗类)
总结:
-
在搜索方法时,是按照mro 的输出结果从左向右的顺序查找的
-
如果在当前类中找到方法,就直接执行,不再搜索
-
如果没有找到,就查找下一个类中是否有对应的方法,如果找到,就直接执行,不再搜索
-
如果找到最后一个类,还没有找到方法,程序报错
多继承和多层继承类似
练习:
定义一个父类Animal,类中包含3个函数,在定义一个子类Cat继承Animal,子类中定义一个函数,对子类进行实例化,使用子类,输出结果
# 定义父类
class Animal:
# 定义函数
def eat(self,n,f):
self.name = n
self.food = f
print(f'{self.name}喜欢吃:{self.food}')
def run(self,d):
self.address = d
print(f'{self.name}正在{self.address}奔跑')
def show(self):
print(f'名称:{self.name},喜欢吃:{self.food}')
# 定义子类
class Cat(Animal):
def call(self):
print('喵喵喵...')
def sleep(self,n1):
self.name = n1
print(f'{self.name}正在睡觉')
# 定义子类
class Kitty(Cat):
def talk(self):
print('我可以说话....')
# 子类实例化
cat = Cat()
# 使用子类
cat.sleep('蓝猫') # 调用自己函数
cat.call()
cat.eat('波斯猫','鲨鱼') # 调用父类函数
cat.show()
cat.run('森林')
print('-----------------------------')
# Kitty子类实例化
ky = Kitty()
# 使用子类
ky.talk() # 调用自己函数
ky.sleep('Kitty') # 调用父类函数
ky.call() # 调用父类函数
ky.eat('Kitty','电') # 调用Animal函数
ky.show() # 调用Animal函数
ky.run('路上') # 调用Animal函数
输出:
蓝猫正在睡觉
喵喵喵...
波斯猫喜欢吃:鲨鱼
名称:波斯猫,喜欢吃:鲨鱼
波斯猫正在森林奔跑
-----------------------------
我可以说话....
Kitty正在睡觉
喵喵喵...
Kitty喜欢吃:电
名称:Kitty,喜欢吃:电
Kitty正在路上奔跑
❤ 新式类和旧式(经典)类
object是python为所有对象提供的基类,提供一些内置的属性和方法,可以使用dir函数来查看。
-
新式类:以
object
为基类的类,推荐使用 -
经典类:不以object为基类的类,不推荐使用
-
在 Python3.x 以后定义类时,如果没有指定父类,这个类会默认继承自 object,所以,python3.x版本定义的类都是新式类。
-
在Python2.x中定义类时,如果没有指定父类,则不会继承自object.
为了保证代码在Python2.x和Python3.x中都能够运行,在定义类时,如果一个类没有父类,建议统一继承自'object'
class 类名(object):
pass