*super函数(超类)

2024-02-11 17:30
文章标签 函数 super 超类

本文主要是介绍*super函数(超类),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

super()函数是用于调用父类(超类)的一个方法

super()是用来解决多继承问题的,直接用类名调用父类中的方法在单继承中不会出现问题,但是在多继承中会涉及到查找顺序(MRO),重复调用(钻石继承)等种种问题。
MRO 就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表。

重复调用(钻石继承)代码演示:

class Parent(object):def __init__(self,name):print('parent的init开始被调用')self.name = nameprint('parent的init结束被调用')class Son1(Parent):def __init__(self,name,age):print('Son1的init开始被调用')self.age = ageParent.__init__(self,name)print('Son1的init结束被调用')class Son2(Parent):def __init__(self,name,gender):print('Son2的init开始被调用')self.gender = genderParent.__init__(self,name)print('Son2的init结束被调用')class Grandson(Son1,Son2):def __init__(self,name,age,gender):print('Grandsond的init开始被调用')Son1.__init__(self,name,age)    # 单独调用父类的初始化方法Son2.__init__(self,name,gender)print('Grandson的init结束被调用')gs = Grandson('grandson',12,'男')
print('姓名',gs.name)
print('年龄',gs.age)
print('性别',gs.gender)

代码理解:

以上代码,子类调用父类中的方法书通过这种方式:
父类名.init(self,xxx) 例如:Parent.init(self,name)

1.过程:

首先整体上来看,这是多继承,Son1和Son2俩个类都继承了Parent类,Grandson类又继承了Son1和Son2俩个类。当实例化类的时候,会调用Grandson中的初始化方法__init__,但是现在要特别注意一件事,一定是先调用Grandson它自己的init方法,然后想法设法在它自己的init方法中调用上面的Son1,Son2,以及Parent中的init方法
然后思考,在Grandson中的init方法下又有Son1.init(self,name,age) 和 Son2.init(self,name,gender) ,注意,Python中的代码是从上往下来执行,因此,这里先执行Son1.init(self,name,age),而这中语法格式就是调用了Son1中的init方法,然后按照思路看Son1下的init方法,它的init方法下又调用了Parent的init方法:Parent.init(self,name),然后又执行Parent的init方法,执行的结果返回给Son1,然后又返回给Grandson,到此为止Son1.init(self,name,age)这句代码就执行完毕了。
而下面这句代码 Son2.init(self,name,gender),执行方式和Son1.init(self,name,age)一样,最终都要调用Parent的init方法。

配图:
在这里插入图片描述
2.代码评价:
说明一下这种格式:父类名.init(self,xxx) 的缺点
在实例化类的时候,传入了三个参数:‘grandson’,12,‘男’
然后看代码的执行结果:

Grandsond的init开始被调用
Son1的init开始被调用
parent的init开始被调用   *
parent的init结束被调用	*
Son1的init结束被调用
Son2的init开始被调用
parent的init开始被调用	*
parent的init结束被调用	*
Son2的init结束被调用
Grandson的init结束被调用
姓名 grandson
年龄 12
性别 男

注意我这里用*标记的代码,结果表明Parent类被重复调用了俩次。打个比方:孙子有三个吃的(三个参数),他的爸爸和他的大爷(Son1,Son2)也需要吃,然后他将吃的传给了他爸爸和他大爷,他爸爸和他大爷吃完发现他爷爷(Parent)也要吃,然后又先后传给了他爷爷,这样他爷爷既吃了他爸的,也吃了他大爷的,就是说他爷爷吃了俩遍,这里只有俩个儿子,所以就吃了俩遍,要是儿子多的话,他爷爷还不得吃死啊,所以最好每个人只吃一次就行。
所以说,Parent类最好被调用一次,要避免重复调用。

super()函数则能解决此问题,这里也要解释一下

MRO

再看如下代码:

class Parent(object):def __init__(self,name,*args,**kwargs): # 为避免多重继承报错print('parent的init开始被调用')self.name = nameprint('parent的init结束被调用')class Son1(Parent):def __init__(self,name,age,*args,**kwargs):	# 为避免多重继承报错print('Son1的init开始被调用')self.age = agesuper().__init__(name,*args,**kwargs)print('Son1的init结束被调用')class Son2(Parent):def __init__(self,name,gender,*args,**kwargs):	# 为避免多重继承报错print('Son2的init开始被调用')self.gender = gendersuper().__init__(name,*args,**kwargs)print('Son2的init结束被调用')class Grandson(Son1,Son2):def __init__(self,name,age,gender):print('Grandsond的init开始被调用')super().__init__(name,age,gender)print('Grandson的init结束被调用')print(Grandson.__mro__)gs = Grandson('grandson',12,'男')
print('姓名',gs.name)
print('年龄',gs.age)
print('性别',gs.gender)

代码理解:

1.过程:
实例化的时候自动调用Grandson中的init方法,当代码执行到super的时候,会先找Son1中的init方法,当在Son1的init方法中执行到super时,注意,这里并不会去找Parent中的init方法,而是会去找和它同级的Son2中的init方法,当在Son2中的init方法中执行到super时,然后才会去找Parent中的init方法。

配图:
在这里插入图片描述
2.代码评价:
看代码执行的结果:

(<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)
Grandsond的init开始被调用
Son1的init开始被调用
Son2的init开始被调用
parent的init开始被调用	*
parent的init结束被调用	*
Son2的init结束被调用
Son1的init结束被调用
Grandson的init结束被调用
姓名 grandson
年龄 12
性别 男

我这里再次用*标记,结果表明Parent类只被调用了一次
用super函数明显避免了一个问题,那就是重复调用(钻石继承),最终Parent类只被调用了一次。效果明显!
这里再说明一下__mro__方法:
print(Grandson.mro)的执行结果就是整个代码类的继承顺序,方法解析顺序表是以一个元组的形式呈现
(<class ‘main.Grandson’>, <class ‘main.Son1’>, <class ‘main.Son2’>, <class ‘main.Parent’>, <class ‘object’>) 先是Grandson然后是Son1,然后是Son2,然后是Parent,最后是Object(Python3中默认继承的是object)

补充:

类方法重写的三种形式:

  1. 父类名.init(self,xxx,xxx):

  2. super().init(xxx,xxx)

  3. super(父类,self).init(xxx,xxx)

以上所有通过对比说明了前俩种方法,而第三种方法和第二种的区别我用MRO顺序表来说明:
就拿上方代码来说明,如果将Grandson类中的

super().__init__(name,age,gender)

改为

super(Son,self).__init__(name,age,gender)

当然结果会报错,但我就表明一下意思,就是说改了之后,按照MRO顺序表来看,他会直接找Parent,从而省略了中间很多索要继承的类,按照这个意思,super().init(name,age,gender)和super(Grandson,self).init(name,age,gender)的结果一样
什么都不写默认从最开始的类向后找。

这篇关于*super函数(超类)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/700391

相关文章

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

GO语言中函数命名返回值的使用

《GO语言中函数命名返回值的使用》在Go语言中,函数可以为其返回值指定名称,这被称为命名返回值或命名返回参数,这种特性可以使代码更清晰,特别是在返回多个值时,感兴趣的可以了解一下... 目录基本语法函数命名返回特点代码示例命名特点基本语法func functionName(parameters) (nam

Python Counter 函数使用案例

《PythonCounter函数使用案例》Counter是collections模块中的一个类,专门用于对可迭代对象中的元素进行计数,接下来通过本文给大家介绍PythonCounter函数使用案例... 目录一、Counter函数概述二、基本使用案例(一)列表元素计数(二)字符串字符计数(三)元组计数三、C

Python中的filter() 函数的工作原理及应用技巧

《Python中的filter()函数的工作原理及应用技巧》Python的filter()函数用于筛选序列元素,返回迭代器,适合函数式编程,相比列表推导式,内存更优,尤其适用于大数据集,结合lamb... 目录前言一、基本概念基本语法二、使用方式1. 使用 lambda 函数2. 使用普通函数3. 使用 N

MySQL中REPLACE函数与语句举例详解

《MySQL中REPLACE函数与语句举例详解》在MySQL中REPLACE函数是一个用于处理字符串的强大工具,它的主要功能是替换字符串中的某些子字符串,:本文主要介绍MySQL中REPLACE函... 目录一、REPLACE()函数语法:参数说明:功能说明:示例:二、REPLACE INTO语句语法:参数

python中update()函数的用法和一些例子

《python中update()函数的用法和一些例子》update()方法是字典对象的方法,用于将一个字典中的键值对更新到另一个字典中,:本文主要介绍python中update()函数的用法和一些... 目录前言用法注意事项示例示例 1: 使用另一个字典来更新示例 2: 使用可迭代对象来更新示例 3: 使用

Python lambda函数(匿名函数)、参数类型与递归全解析

《Pythonlambda函数(匿名函数)、参数类型与递归全解析》本文详解Python中lambda匿名函数、灵活参数类型和递归函数三大进阶特性,分别介绍其定义、应用场景及注意事项,助力编写简洁高效... 目录一、lambda 匿名函数:简洁的单行函数1. lambda 的定义与基本用法2. lambda

Python 函数详解:从基础语法到高级使用技巧

《Python函数详解:从基础语法到高级使用技巧》本文基于实例代码,全面讲解Python函数的定义、参数传递、变量作用域及类型标注等知识点,帮助初学者快速掌握函数的使用技巧,感兴趣的朋友跟随小编一起... 目录一、函数的基本概念与作用二、函数的定义与调用1. 无参函数2. 带参函数3. 带返回值的函数4.

MySQL中DATE_FORMAT时间函数的使用小结

《MySQL中DATE_FORMAT时间函数的使用小结》本文主要介绍了MySQL中DATE_FORMAT时间函数的使用小结,用于格式化日期/时间字段,可提取年月、统计月份数据、精确到天,对大家的学习或... 目录前言DATE_FORMAT时间函数总结前言mysql可以使用DATE_FORMAT获取日期字段

Django中的函数视图和类视图以及路由的定义方式

《Django中的函数视图和类视图以及路由的定义方式》Django视图分函数视图和类视图,前者用函数处理请求,后者继承View类定义方法,路由使用path()、re_path()或url(),通过in... 目录函数视图类视图路由总路由函数视图的路由类视图定义路由总结Django允许接收的请求方法http