找回密码
 会员注册
查看: 21|回复: 0

python中super用法

[复制链接]

3

主题

0

回帖

10

积分

新手上路

积分
10
发表于 2024-9-6 00:13:57 | 显示全部楼层 |阅读模式
目录前言一.super是什么二.super().__init__()三.继承顺序前言  在python继承的时候经常会遇到super这个东西,搞得不是太明白,写下这篇博文记录一下。我这里用的是python3版本。一.super是什么先来看下super是什么,怎么用的,具体后面介绍?super是一个内置函数,用于调用父类(超类)的方法。它提供了一种方便的方式来调用父类的方法,而不需要显式地指定父类的名称。super函数通常在子类的方法中使用。当你在子类中重写一个方法时,可以使用super函数来调用父类的相同方法。这样可以在不破坏继承关系的前提下,扩展或修改父类的行为。super函数接受两个参数:子类的类名和子类的实例,即super(子类类名,self).__init__()它返回一个特殊的对象,该对象可以用于调用父类的方法。通过super函数返回的对象,可以在子类中直接调用父类的方法,而无需显式指定父类的名称。在python3中已经简化了这种写法:直接写成super().__init__()。看个例子classParentClass:def__init__(self):self.parent_var=10defsome_method(self):print("ParentClassmethod")classChildClass(ParentClass):def__init__(self):super().__init__()#调用父类的初始化方法self.child_var=20defsome_method(self):super().some_method()#调用父类的方法print("ChildClassmethod")child_obj=ChildClass()child_obj.some_method()1234567891011121314151617181920把上面的代码改成类名继承看下:classParentClass:def__init__(self):self.parent_var=10defsome_method(self):print("ParentClassmethod")classChildClass(ParentClass):def__init__(self)arentClass.__init__(self)#调用父类的初始化方法self.child_var=20defsome_method(self)arentClass.some_method(self)#调用父类的方法print("ChildClassmethod")child_obj=ChildClass()child_obj.some_method()1234567891011121314151617181920输出:ParentClassmethodChildClassmethod12  通过对比可以看到通过super可以直接替代类名从而简便继承方式。其实super对于普通函数的继承很好理解,就是直接通过super().xxx()即可调用父类的方法。我们下面重点介绍下经常让人困惑的super().__init__()。二.super().__init__()  在理解super().__init__()的时候也可以直接把他当做继承普通的函数一样,只不过这里是继承父类的构造函数。既然是继承父类的构造函数,那么在继承的时候同样出现一种现象,那就是重写(有些人叫覆盖,个人感觉叫做重写更严谨),重写顾名思义就是父类已经有了这个函数了,子类中又写了一遍。根据强龙不压地头蛇的原则,那么在使用的时候如果发生了重写,就要以子类的函数为准。看个例子:classA:def__init__(self):print("调用A")classB(A):def__init__(self):print("调用B")b=B()123456789输出:调用B1  上面的代码可以发现,虽然B继承了A,但是构造函数重写了,所以在调用实例化B的时候调用的还是B本身的构造函数,可以理解为父类的构造函数被覆盖了。如果我还想调用父类的怎么办呢,如果你能想到继承,说明你基本上已经明白了,我们直接看例子:classA:def__init__(self):print("调用A")classB(A):def__init__(self):super().__init__()print("调用B")b=B()12345678910输出:调用A调用B12再来看个稍微复杂点的例子:classParentClass:def__init__(self,x):self.parent_var=xdefsome_method(self):print("ParentClassmethod")classChildClass(ParentClass):def__init__(self,x,y):super().__init__(x)#继承父类的构造函数self.child_var=ychild_obj=ChildClass(10,20)print(child_obj.parent_var)#访问继承的父类属性print(child_obj.child_var)#访问子类属性1234567891011121314151617输出:102012子类中并没有parent_var这个属性,但是可以通过继承父类的构造函数获取到这个属性。三.继承顺序  当发生多继承的时候他的顺序是什么样的,如下面的一段代码C这个子类在继承父类的初始化函数的时候到底继承的是A的还是B的?classA:def__init__(self):print('A')classB:def__init__(self):print('B')classC(A,B):def__init__(self):print('C')super().__init__()c=C()12345678910111213141516我们看一下输出结果是什么:CA12  为什么输出的是C,A呢?这里涉及到Python中的菱形继承。菱形继承的原则是继承的两个父类时并列的。按照继承的父类从左至右的顺序查找的,如果在当前类中找到方法,就直接执行,不再进行搜索,如果没有找到就查找下一个继承的父类中是否有对应的方法,如果找到,就直接执行,不再搜索,如果找到最后一个类,还没有找到方法,程序报错。根据上面的原则,我们来看一个复杂点的多继承:classA:def__init__(self):print('A')classB(A):def__init__(self):print('B')super().__init__()classC(A):def__init__(self):print('C')super().__init__()classD(A):def__init__(self):print('D')super().__init__()classE(B,C):def__init__(self):print('E')super().__init__()classF(C,D):def__init__(self):print('F')super().__init__()classG(E,F):def__init__(self):print('G')super().__init__()g=G()1234567891011121314151617181920212223242526272829303132333435363738394041输出:GEBFCDA1234567  根据输出结果可以看到G继承自E,F是并列的,初始化的时候不会先把E初始化完毕才初始化F。也可以通过Python自带的__mro__查看一下继承顺序:print(G.__mro__)1输出:(,,,,,,,)1至此关于super的基本介绍就已经讲完了,如有错误,敬请指正!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2025-1-9 19:15 , Processed in 0.451824 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表