继承
继承的概念
生活中的继承,—般指的是子女继承父辈的财产。
经典类和新式类
- 经典类(旧式类)
python2
class 类名:
pass
- 新式类
python3
class 类名(object):
pass
体验继承
Python面向对象的继承指的是多个类之间的所属关系,即子类默认继承父类的所有属性和方法,具体如下:
# 类A
class A(object):
def __init__(self):
self.num = 1
def info_print(self):
print(self.num)
# 类B
class B(A):
pass
result = B()
result.info_print()
在Python中,所有类默认继承object类,object类是顶级类或基类;其他子类叫做派生类。
单继承
故事主线:一个煎饼果子老师傅,在煎饼果子界摸爬滚打多年,研发了一套精湛的摊煎饼果子的技术。师父要把这套技术传授给他的唯一的最得意的徒弟。
分析:徒弟是不是要继承师父的所有技术?
# 1.师傅类
class Master(object):
def __init__(self):
self.kongfu = '蟹黄堡牌煎饼果子秘方'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')
# 2.徒弟类
class Prentice(Master):
pass
# 3.创建对象
zhangshan = Prentice()
# 4.访问实例属性
print(zhangshan.kongfu)
zhangshan.make_cake()
'''
蟹黄堡牌煎饼果子秘方
运用蟹黄堡牌煎饼果子秘方制作煎饼果子
'''
多继承
故事推进: zhangsan是个爱学习的好孩子,想学习更多的煎饼果子技术,于是,在百度搜索到老王煎饼铺,报班学习煎饼果子技术。
所谓多继承意思就是一个类同时继承了多个父类。
class Master(object):
def __init__(self):
self.kongfu = '蟹黄堡牌煎饼果子秘方'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')
# 老王煎饼铺类
class School(object):
def __init__(self):
self.kongfu = '老王牌煎饼果子秘方'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')
class Prentice(School, Master):
pass
zhangshan = Prentice()
print(zhangshan.kongfu)
zhangshan.make_cake()
'''
老王牌煎饼果子秘方
运用老王牌煎饼果子秘方制作煎饼果子
'''
注意: 当一个类有多个父类的时候,默认使用第一个父类的同名属性和方法**。
子类重写父类同名方法和属性
故事: zhangsan掌握了师父和培训的技术后,自己潜心钻研出自己的独门配方的一套全新的煎饼果子技术。
class Master(object):
def __init__(self):
self.kongfu = '蟹黄堡牌煎饼果子秘方'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')
# 老王煎饼铺类
class School(object):
def __init__(self):
self.kongfu = '老王牌煎饼果子秘方'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')
class Prentice(School, Master):
def __init__(self):
self.kongfu = '独创煎饼果子配方'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')
zhangshan = Prentice()
print(zhangshan.kongfu)
zhangshan.make_cake()
'''
独创煎饼果子配方
运用独创煎饼果子配方制作煎饼果子
'''
注意:如果子类和父类拥有同名属性和方法,子类创建对象调用属性和方法的时候,调用到的是子类里面的同名属性和方法。
MRO继承顺序
MRO(Method Resolution Order)是用于确定多继承类中方法解析顺序的算法。当一个类继承自多个父类时,Python 使用MRO来决定方法查找的顺序,以确保在方法被调用时能够正确地找到继承链中的对应方法。
MRO使用C3线性化算法来生成一个有序的方法解析列表。具体来说,对于一个类及其父类的继承关系,MRO会按照如下规则生成方法解析顺。
- 首先,子类的MRO列表中会先包含类本身。
- 然后,MRO列表会按照类的继承顺序依次包含每个直接父类。如果一个类继承自多个父类,那么父类在MRO列表中出现的顺序将会保持从左到右的继承顺序。
- 接着,对于每个直接父类,MRO会按照同样的规则递归地包含其所有基类。在递归过程中,如果多个类共享相同的基类,那么该基类只会在MRO列表中出现一次,并且会保持从左到右的继承顺
---omit---
print(Prentice.__mro__)
'''
(<class '__main__.Prentice'>, <class '__main__.School'>, <class '__main__.Master'>, <class 'object'>)
'''
子类调用父类的同名方法和属性
故事:很多顾客都希望也能吃到蟹黄堡牌和老王牌的技术的煎饼果子。
class Master(object):
def __init__(self):
self.kongfu = '蟹黄堡牌煎饼果子秘方'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')
class School(object):
def __init__(self):
self.kongfu = '老王牌煎饼果子秘方'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')
class Prentice(School, Master):
def __init__(self):
self.kongfu = '独创煎饼果子配方'
def make_cake(self):
# 如果是先调用了父类的属性和方法,父类属性会覆盖子类属性,故在调用属性前,先调用自己子类的初始化
self.__init__() # 这里不需要self形参
print(f'运用{self.kongfu}制作煎饼果子')
# 调用父类方法,但是为了保证调用到的也是父类的属性,必须在调用方法前调用父类的初始化
def make_master_cake(self):
Master.__init__(self)
Master.make_cake(self)
def make_school_cake(self):
School.__init__(self)
School.make_cake(self)
if __name__ == '__main__':
zhangshan = Prentice()
多层继承
故事:N年后, zhangsan老了,想要把所有技术传承给自己的徒弟。
class Master(object):
def __init__(self):
self.kongfu = '蟹黄堡牌煎饼果子秘方'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')
class School(object):
def __init__(self):
self.kongfu = '老王牌煎饼果子秘方'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')
class Prentice(School, Master):
def __init__(self):
self.kongfu = '独创煎饼果子配方'
def make_cake(self):
self.__init__()
print(f'运用{self.kongfu}制作煎饼果子')
def make_master_cake(self):
Master.__init__(self)
Master.make_cake(self)
def make_school_cake(self):
School.__init__(self)
School.make_cake(self)
# 徒孙类
class Tusun(Prentice):
pass
if __name__ == '__main__':
lisi = Tusun()
lisi.make_cake()
lisi.make_master_cake()
lisi.make_school_cake()
'''
运用独创煎饼果子配方制作煎饼果子
运用蟹黄堡牌煎饼果子秘方制作煎饼果子
运用老王牌煎饼果子秘方制作煎饼果子
'''
super()调用父类方法
比如有这样一个需求,zhangsan需要同时调用父类master和school的方法
写法有两种:
- super(当前类名, self).函数()
- super().函数()
class Master(object):
def __init__(self):
self.kongfu = '蟹黄堡牌煎饼果子秘方'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')
class School(Master):
def __init__(self):
self.kongfu = '老王牌煎饼果子秘方'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')
# super 带参数写法
# super(School, self).__init__()
# super(School, self).make_cake()
# super 无参数写法
super().__init__()
super().make_cake()
class Prentice(School):
def __init__(self):
self.kongfu = '独创煎饼果子配方'
def make_cake(self):
self.__init__()
print(f'运用{self.kongfu}制作煎饼果子')
def make_master_cake(self):
Master.__init__(self)
Master.make_cake(self)
def make_school_cake(self):
School.__init__(self)
School.make_cake(self)
def make_old_cake(self):
# 方法一:如果父类名修改,这里也要修改;代码量大,冗余
# Master.__init__(self)
# Master.make_cake(self)
# School.__init__(self)
# School.make_cake(self)
# 方法二:supper()
# super(当前类名, self).函数()
# super(Prentice, self).__init__()
# super(Prentice, self).make_cake()
# 这种方法当自己类类名变化时,也要修改,并且较第一种代码数量没有减少
# super().函数() 无参数
super().__init__()
super().make_cake()
# 徒孙类
class Tusun(Prentice):
pass
if __name__ == '__main__':
lisi = Tusun()
lisi.make_old_cake()
'''
运用老王牌煎饼果子秘方制作煎饼果子
运用蟹黄堡牌煎饼果子秘方制作煎饼果子
'''
私有权限
定义私有属性和方法
在Python中,可以为实例属性和方法设置私有权限,即设置某个实例属性或实例方法不继承给子类。
故事: zhangsan把技术传承给徒弟的同时,不想把自己的钱(2000000个亿)继承给徒弟,这个时候就要为钱这个实例属性设置私有权限。
设置私有权限的方法: 在属性名和方法名前面加上两个下划线__。
class Master(object):
def __init__(self):
self.kongfu = '蟹黄堡牌煎饼果子秘方'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')
class School(Master):
def __init__(self):
self.kongfu = '老王牌煎饼果子秘方'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')
class Prentice(School):
def __init__(self):
self.kongfu = '独创煎饼果子配方'
self.__money = 20000
def make_cake(self):
self.__init__()
print(f'运用{self.kongfu}制作煎饼果子')
# 徒孙类
class Tusun(Prentice):
pass
if __name__ == '__main__':
lisi = Tusun()
print(lisi.__money)
'''
AttributeError Traceback (most recent call last)
Cell In[25], line 30
28 if __name__ == '__main__':
29 lisi = Tusun()
---> 30 print(lisi.__money)
AttributeError: 'Tusun' object has no attribute '__money'
'''
获取和修改私有属性值
在Python中,一般定义函数名get_xx用来获取私有属性,定义set_xx用来修改私有属性值。
class Master(object):
def __init__(self):
self.kongfu = '蟹黄堡牌煎饼果子秘方'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')
class School(Master):
def __init__(self):
self.kongfu = '老王牌煎饼果子秘方'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')
class Prentice(School):
def __init__(self):
self.kongfu = '独创煎饼果子配方'
self.__money = 20000
# 获取私有属性值
def get_money(self):
return self.__money
# 修改私有属性值
def set_money(self, money):
self.__money = money
def make_cake(self):
self.__init__()
print(f'运用{self.kongfu}制作煎饼果子')
# 徒孙类
class Tusun(Prentice):
pass
if __name__ == '__main__':
lisi = Tusun()
print(lisi.get_money())
lisi.set_money(500)
print(lisi.get_money())
'''
20000
500
'''
`