文章目录
目标
- 继承的概念
- 单继承
- 多继承
- 子类重写父类的同名属性和方法
- 子类调用父类的同名属性和方法
- 多层继承
- super()
- 私有属性和私有方法
一. 继承的概念
生活中的继承,一般指的是子女继承父辈的财产。
- 拓展1:经典类或旧式类
不由任意内置类型派生出的类,称之为经典类。 [经典类 甚至连Object父类都没有了]
class 类名:
代码
......
- 拓展2:新式类
class 类名(object):
代码
区别:
Python中类分两种:旧式类和新式类:
新式类都从object继承,经典类不需要。
新式类的MRO(method resolution order 基类搜索顺序)算法采用C3算法广度优先搜索,而旧式类的MRO算法是采用深度优先搜索
新式类相同父类只执行一次构造函数,经典类重复执行多次。
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() # 继承了父类A的所有方法
result.info_print() # 1
在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. 创建对象 daqiu
daqiu = Prentice()
# 继承了师傅的方法
daqiu.make_cake() # 运用[古法煎饼果子配方]制作煎饼果子
三. 多继承 [python又支持多继承了]
故事推进:daqiu 是个爱学习的好孩子,想学习更多的煎饼果子技术,于是,在百度搜索,报班学习煎饼果子技术。
所谓多继承意思就是一个类同时继承了多个父类。
class Master(object):
def __init__(self):
self.kongfu = '[古法煎饼果子配方]'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')
def sayPlay(self):
print("老师傅独有技能:唱戏曲")
class School(object):
def __init__(self):
self.kongfu = '[武大煎饼果子配方]'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')
def findWork(self):
print('学校独有技能:找工作')
class Prentice(School,Master): # 多继承 同时继承2个类
pass
daqiu = Prentice()
# 先是两位老师傅那分别学的独家技能
daqiu.sayPlay()
daqiu.findWork()
# 再是共同的技能
daqiu.make_cake() # 默认使用第一个父类的同名属性和方法
注意:当一个类有多个父类的时候,默认使用第一个父类的同名属性和方法。
四. 子类重写父类同名方法和属性
故事:daqiu掌握了师父和培训的技术后,自己潜心钻研出自己的独门配方的一套全新的煎饼果子技术。
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}制作煎饼果子')
daqiu = Prentice()
print(daqiu.kongfu)
daqiu.make_cake()
# 为了方便且快速地看清继承关系和顺序,可以用__mro__方法来获取这个类的调用顺序。
print(Prentice.__mro__)
子类和父类具有同名属性和方法,默认使用子类的同名属性和方法。(重写了嘛 当然是啦 就近 更近)
为了方便且快速地看清继承关系和顺序,可以用__mro__方法来获取这个类的调用顺序。
五. 子类调用父类的同名方法和属性
比较麻烦,要专门写一个方法调用
只是记得可以调就是了
故事:很多顾客都希望也能吃到古法和黑马的技术的煎饼果子。
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):
# 如果是先调用了父类的属性和方法,父类属性会覆盖子类属性,故在调用属性前,先调用自己子类的初始化
# ★ 不加此行 调用了下面的的方法后 再调用这个方法就会有问题 kongfu的值会被频繁的改
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)
# Master.make_cake() # 外面可以直接调 但是报错 因为没有对象啊
daqiu = Prentice()
daqiu.make_cake()
daqiu.make_master_cake()
daqiu.make_school_cake()
# 对象.方法() 会自动将当前对象当作self传进去
daqiu.make_cake() # self.kongfu还是保持School的
对象.方法() 会自动将当前对象当作self传进去
六. 多层继承
故事:N年后,daqiu老了,想要把所有技术传承给自己的徒弟。
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
xiaoqiu = Tusun()
xiaoqiu.make_cake()
xiaoqiu.make_school_cake()
xiaoqiu.make_master_cake()
七. super()调用父类方法
继承关系: Master->School->Prentice (爷->父->儿)
场景: Master有make_cake方法,School重写了make_cake方法,Prentice又重写了make_cake方法
目前有3个make_cake方法 我想在Prentice类里面同时能调用到这3个make_cake方法,怎么做呢?
方法一:原始笨方法
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 = '[独创煎饼果子技术]'
def make_cake(self):
self.__init__()
print(f'运用{self.kongfu}制作煎饼果子')
# 代码在这 前面都直接复制的,一样(唯一改了一个继承关系: School(Master):)
# 一次性调用父类的同名属性和方法
def make_old_cake(self):
# 方法一:代码冗余;父类类名如果变化,这里代码需要频繁修改
# 分别调用两次init和两次对应方法
Master.__init__(self)
Master.make_cake(self)
School.__init__(self)
School.make_cake(self)
daqiu = Prentice()
daqiu.make_old_cake()
方法二:super带参写法
好多了 但非最佳, 也不是很推荐
注意:使用super() 可以自动查找父类。调用顺序遵循
__mro__
类属性的顺序。比较适合单继承使用。
super指的是直接父类 (子的super=父,父的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调用一下
# 方法2: super带参 这里也要加代码
super(School,self).__init__()
super(School,self).make_cake()
class Prentice(School):
def __init__(self):
self.kongfu = '[独创煎饼果子技术]'
def make_cake(self):
self.__init__()
print(f'运用{self.kongfu}制作煎饼果子')
# 本节代码在这: 一次性调用父类的同名属性和方法
def make_old_cake(self):
# 方法二: super
# 方法2 带参写法: super(当前类名,self).函数
super(Prentice,self).__init__()
super(Prentice,self).make_cake() # 运用[黑马煎饼果子配方]制作煎饼果子
# 确实调用到了父类 但是只调用到了爸爸,没有调用到爷爷
# 怎么办呢? 答: 爸爸方法里也要这么写一份 (我的super是爸爸,爸爸的super才是爷爷 super是直接父类)
daqiu = Prentice()
daqiu.make_old_cake()
方法三: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}制作煎饼果子')
# 方法3 父类要加的代码 就是每个子类都主动调用一下父类的该方法即可
super().__init__()
super().make_cake()
class Prentice(School):
def __init__(self):
self.kongfu = '[独创煎饼果子技术]'
def make_cake(self):
self.__init__()
print(f'运用{self.kongfu}制作煎饼果子')
# 方法三: 无参super
def make_old_cake(self):
super().__init__()
super().make_cake()
daqiu = Prentice()
daqiu.make_old_cake()
注意:使用super() 可以自动查找父类。调用顺序遵循
__mro__
类属性的顺序。比较适合单继承使用。
super指的是直接父类 (子的super=父,父的super=爷)
八. 私有权限
8.1 定义私有属性和方法
在Python中,可以为实例属性和方法设置私有权限,即设置某个实例属性或实例方法不继承给子类。
故事:daqiu把技术传承给徒弟的同时,不想把自己的钱(2000000个亿)继承给徒弟,这个时候就要为
钱
这个实例属性设置私有权限。
设置私有权限的方法:在属性名和方法名 前面 加上两个下划线 __。
不愧是python 命名规则就是私有属性的语法
class Father(object):
def __init__(self):
self.kongfu = '[独创热干面配方]'
# 定义私有属性
self.__money = 2000000
# 定义私有方法
def __info_print(self):
print(self.kongfu)
print(self.__money)
def make_cake(self):
self.__init__()
print(f'运用{self.kongfu}制作煎饼果子')
class Son(Father):
def print_info(self):
print(self.kongfu) # 能继承到的 都能正常访问 但一定得"对象.xx"的形式 因为都属于对象
self.make_cake()
# self.__money # 报错 私有的怎么也访问不到
# self.__info_print() # 报错 私有的怎么也访问不到
fa = Father()
#print(fa.__money) # AttributeError: 'Father' object has no attribute '__money'
#fa.__info_print # AttributeError: 'Father' object has no attribute '__info_print'
#结论: 私有属性和私有方法都不能在类外访问
## 非私有属性方法才可以正常访问
print(fa.kongfu)
fa.make_cake()
son = Son()
# print(son.__money) # AttributeError: 'Son' object has no attribute '__money'
# son.__info_print() # AttributeError: 'Son' object has no attribute '__info_print'
#结论: 私有属性和私有方法 肯定不会被继承的
# 非私有属性和方法 才可以正常被继承
print(son.kongfu)
son.make_cake()
注意:私有属性和私有方法只能在类里面访问和修改。
8.2 获取和修改私有属性值
在Python中,一般定义函数名get_xx
用来获取私有属性,定义set_xx
用来修改私有属性值。
class Prentice(object):
def __init__(self):
self.kongfu = '[独创煎饼果子配方]'
self.__money = 2000000
# 获取私有属性
def get_money(self):
return self.__money # 和java一样 利用私有属性只能在类内访问这一特点
# 修改私有属性
def set_money(self,money):
self.__money = money # 和java一样 利用私有属性只能在类内访问这一特点
def __info_print(self):
print(self.kongfu)
print(self.__money)
def make_cake(self):
self.__init__()
print(f'运用{self.kongfu}制作煎饼果子')
# 徒孙类
class Tusun(Prentice):
pass
xq = Tusun()
# 私有属性用访问器访问
print(xq.get_money()) # 2000000
xq.set_money(10)
print(xq.get_money()) # 10
# 非私有属性正常访问
print(xq.kongfu) # [独创煎饼果子配方]
xq.kongfu= '[独创热干面配方]'
print(xq.kongfu) # [独创热干面配方]
# print(Prentice.kongfu) # type object 'Prentice' has no attribute 'kongfu'
# 都是非静态的成员 属于对象 而不属于类
九. 总结
-
继承的特点
- 子类默认拥有父类的所有属性和方法
- 子类重写父类同名方法和属性
- 子类调用父类同名方法和属性
-
super()方法快速调用父类方法
-
私有权限
- 不能继承给子类的属性和方法需要添加私有权限
- 语法
class 类名(): # 私有属性 __属性名 = 值 # 私有方法 def __函数名(self): 代码
小笔记:
对象.方法() 会自动将当前对象当作self传进去