目录
在子类中如果有和父类同名的方法,则通过子类实例去调用该方法时,会调用子类中的该方法而不是父类的方法,这个特点我们成为叫做方法的重写(覆盖: override
)。
故事继续:徒弟掌握了师父和学院派技术后,自己潜心钻研出自己的独门配方的一套全新的煎饼果子技术。
# 1.创建师父类,属性和方法 class Master(object): def __init__(self): self.kongfu = '[古法煎饼果子配方]' def make_cake(self): print(f'运用{self.kongfu}制作煎饼果子') # 2.创建学院派类 属性和方法 class School(object): def __init__(self): self.kongfu = '[学院派煎饼果子配方]' def make_cake(self): print(f'运用{self.kongfu}制作煎饼果子') # 3.独创配方 class Prentice(School, Master): def __init__(self): self.kongfu = '[独创煎饼果子配方]' def make_cake(self): print(f'运用{self.kongfu}制作煎饼果子') # 4. 用徒弟类创建对象,调用实例属性和方法 tudi = Prentice() print(tudi.kongfu) tudi.make_cake() """ 输出结果 [独创煎饼果子配方] 运用[独创煎饼果子配方]制作煎饼果子 """
结论:子类和父类具有同名属性和方法,默认使用子类的同名属性和方法。
拓展:
当我们调用一个对象的方法时,会优先去当前对象中寻找是否具有该方法,如果有则直接调用。
如果没有,则去当前对象的父类中寻找,如果父类中有则直接调用父类中的方法。
如果没有,则去父类的父类中寻找,以此类推,直到找到object,如果依然没有找到,则报错。
在类的继承中,如果重定义某个方法,该方法会覆盖父类的同名方法,但有时,我们希望能同时实现父类的功能,这时,我们就需要调用父类的方法了,可通过使用 super()
函数来实现。
实际需求就是:子类调用父类的同名方法和属性。
故事继续:虽然自己独创的煎饼果子配方非常受欢迎,但是还是有顾客都希望也能吃到古法和学院技术的煎饼果子。
# 1.创建师父类,属性和方法 class Master(object): def __init__(self): self.kongfu = '[古法煎饼果子配方]' def make_cake(self): print(f'运用{self.kongfu}制作煎饼果子') # 2. 定义徒弟类,继承师父类 # 添加和父类同名的属性和方法 class Prentice(Master): def __init__(self): self.kongfu = '[独创煎饼果子配方]' # 子类的make_cake(self)方法 def make_cake(self): """ 加自己的初始化的原因: 如果是先调用了父类的属性和方法,父类属性会覆盖子类属性, 如果不加这个自己的初始化, kongfu属性值是上一次调用的init内的kongfu属性值 执行方式如下: # 创建一个子类对象 tudi = Prentice() # 调用执行父类中的make_cake()方法 tudi.make_master_cake() # 调用子类中的make_cake() tudi.make_cake() 就能看到劫、结果。 所以在调用属性前,先调用自己子类的初始化,要记住。 """ self.__init__() print(f'运用{self.kongfu}制作煎饼果子') # 调用父类的make_cake()方法 # 子类调用父类的同名方法和属性:把父类的同名属性和方法再次封装 # 调用父类方法,但是为保证调用到的也是父类的属性,必须在调用方法前调用父类的初始化 def make_master_cake(self): # 父类类名.函数() # 再次调用初始化的原因:这里想要调用父类的同名方法和属性, # 属性在init初始化位置,所以需要再次调用init Master.__init__(self) Master.make_cake(self) # 3 . 用徒弟类创建对象,调用实例属性和方法 # 创建一个子类对象 tudi = Prentice() # 调用执行父类中的make_cake()方法 tudi.make_master_cake() # 调用子类中的make_cake() tudi.make_cake() """ 输出结果: 运用[古法煎饼果子配方]制作煎饼果子 运用[独创煎饼果子配方]制作煎饼果子 """
方式一: make_master_cake()
方法中的代码冗余;父类类名如果变化,那么在子类中会涉及多处修改,另外,Python是允许多继承的语言,如上所示的方法在多继承时就需要重复写多次,显得累赘。为了解决这些问题,Python提供了 super()
函数解决此问题。
使用 super()
函数调用父类中的同名方法。
# 1.创建师父类,属性和方法 class Master(object): def __init__(self): self.kongfu = '[古法煎饼果子配方]' def make_cake(self): print(f'运用{self.kongfu}制作煎饼果子') # 2. 定义徒弟类,继承师父类 # 添加和父类同名的属性和方法 class Prentice(Master): def __init__(self): self.kongfu = '[独创煎饼果子配方]' # 子类的make_cake(self)方法 def make_cake(self): self.__init__() print(f'运用{self.kongfu}制作煎饼果子') # 调用父类的make_cake()方法 # 子类调用父类的同名方法和属性:把父类的同名属性和方法再次封装 # 调用父类方法,但是为保证调用到的也是父类的属性,必须在调用方法前调用父类的初始化 def make_master_cake(self): # 方法二: super() # super函数需要传递的参数:(当前类名, self)前边是类名,后边是对象 # 方式一: super(当前类名, self).函数() # super(Prentice, self).__init__() # super(Prentice, self).make_cake() # 方式二; 简便方法,使用super().函数(),参数可省略。 super().__init__() super().make_cake() # 3 . 用徒弟类创建对象,调用实例属性和方法 # 创建一个子类对象 tudi = Prentice() # 调用执行父类中的make_cake()方法 tudi.make_master_cake() # 调用子类中的make_cake() tudi.make_cake() """ 输出结果: 运用[古法煎饼果子配方]制作煎饼果子 运用[独创煎饼果子配方]制作煎饼果子 """
注意:使用 super()
函数可以自动查找父类。调用顺序遵循 __mro__
类属性的顺序。比较适合单继承使用。
__mro__
内置类属性说明在Python中快速查看一个类的所继承的父类,以及父类的层级关系的方法,返回的结果是一个元组。
# 如上边示例 # 语法:类名.__mro__ print(Prentice.__mro__) """ 输出结果: (<class '__main__.Prentice'>, <class '__main__.Master'>, <class 'object'>) 可以看到返回的是一个元组, `super()`函数在这个元组的类中,依次查找相关属性或方法。 """