*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函数(超类)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:https://blog.csdn.net/shuyv/article/details/103955885
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/700391

相关文章

Python中bisect_left 函数实现高效插入与有序列表管理

《Python中bisect_left函数实现高效插入与有序列表管理》Python的bisect_left函数通过二分查找高效定位有序列表插入位置,与bisect_right的区别在于处理重复元素时... 目录一、bisect_left 基本介绍1.1 函数定义1.2 核心功能二、bisect_left 与

java中BigDecimal里面的subtract函数介绍及实现方法

《java中BigDecimal里面的subtract函数介绍及实现方法》在Java中实现减法操作需要根据数据类型选择不同方法,主要分为数值型减法和字符串减法两种场景,本文给大家介绍java中BigD... 目录Java中BigDecimal里面的subtract函数的意思?一、数值型减法(高精度计算)1.

C++/类与对象/默认成员函数@构造函数的用法

《C++/类与对象/默认成员函数@构造函数的用法》:本文主要介绍C++/类与对象/默认成员函数@构造函数的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录名词概念默认成员函数构造函数概念函数特征显示构造函数隐式构造函数总结名词概念默认构造函数:不用传参就可以

C++类和对象之默认成员函数的使用解读

《C++类和对象之默认成员函数的使用解读》:本文主要介绍C++类和对象之默认成员函数的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、默认成员函数有哪些二、各默认成员函数详解默认构造函数析构函数拷贝构造函数拷贝赋值运算符三、默认成员函数的注意事项总结一

Python函数返回多个值的多种方法小结

《Python函数返回多个值的多种方法小结》在Python中,函数通常用于封装一段代码,使其可以重复调用,有时,我们希望一个函数能够返回多个值,Python提供了几种不同的方法来实现这一点,需要的朋友... 目录一、使用元组(Tuple):二、使用列表(list)三、使用字典(Dictionary)四、 使

PyTorch中cdist和sum函数使用示例详解

《PyTorch中cdist和sum函数使用示例详解》torch.cdist是PyTorch中用于计算**两个张量之间的成对距离(pairwisedistance)**的函数,常用于点云处理、图神经网... 目录基本语法输出示例1. 简单的 2D 欧几里得距离2. 批量形式(3D Tensor)3. 使用不

MySQL 字符串截取函数及用法详解

《MySQL字符串截取函数及用法详解》在MySQL中,字符串截取是常见的操作,主要用于从字符串中提取特定部分,MySQL提供了多种函数来实现这一功能,包括LEFT()、RIGHT()、SUBST... 目录mysql 字符串截取函数详解RIGHT(str, length):从右侧截取指定长度的字符SUBST

Kotlin运算符重载函数及作用场景

《Kotlin运算符重载函数及作用场景》在Kotlin里,运算符重载函数允许为自定义类型重新定义现有的运算符(如+-…)行为,从而让自定义类型能像内置类型那样使用运算符,本文给大家介绍Kotlin运算... 目录基本语法作用场景类对象数据类型接口注意事项在 Kotlin 里,运算符重载函数允许为自定义类型重

Pandas中统计汇总可视化函数plot()的使用

《Pandas中统计汇总可视化函数plot()的使用》Pandas提供了许多强大的数据处理和分析功能,其中plot()函数就是其可视化功能的一个重要组成部分,本文主要介绍了Pandas中统计汇总可视化... 目录一、plot()函数简介二、plot()函数的基本用法三、plot()函数的参数详解四、使用pl

Python的time模块一些常用功能(各种与时间相关的函数)

《Python的time模块一些常用功能(各种与时间相关的函数)》Python的time模块提供了各种与时间相关的函数,包括获取当前时间、处理时间间隔、执行时间测量等,:本文主要介绍Python的... 目录1. 获取当前时间2. 时间格式化3. 延时执行4. 时间戳运算5. 计算代码执行时间6. 转换为指